xref: /linux/kernel/bpf/syscall.c (revision bbc1d24724e110b86a1a7c3c1724ce0d62cc1e2e)
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 ||
16715c14a3dSBrian Vazquez 		   map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
16815c14a3dSBrian Vazquez 		return map->ops->map_update_elem(map, key, value, flags);
16913b79d3fSLorenz Bauer 	} else if (map->map_type == BPF_MAP_TYPE_SOCKHASH ||
17013b79d3fSLorenz Bauer 		   map->map_type == BPF_MAP_TYPE_SOCKMAP) {
17113b79d3fSLorenz Bauer 		return sock_map_update_elem_sys(map, key, value, flags);
17215c14a3dSBrian Vazquez 	} else if (IS_FD_PROG_ARRAY(map)) {
1733af43ba4SHou Tao 		return bpf_fd_array_map_update_elem(map, map_file, key, value,
17415c14a3dSBrian Vazquez 						    flags);
17515c14a3dSBrian Vazquez 	}
17615c14a3dSBrian Vazquez 
177b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
17815c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
17915c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
18015c14a3dSBrian Vazquez 		err = bpf_percpu_hash_update(map, key, value, flags);
18115c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
18215c14a3dSBrian Vazquez 		err = bpf_percpu_array_update(map, key, value, flags);
18315c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
18415c14a3dSBrian Vazquez 		err = bpf_percpu_cgroup_storage_update(map, key, value,
18515c14a3dSBrian Vazquez 						       flags);
18615c14a3dSBrian Vazquez 	} else if (IS_FD_ARRAY(map)) {
1873af43ba4SHou Tao 		err = bpf_fd_array_map_update_elem(map, map_file, key, value,
18815c14a3dSBrian Vazquez 						   flags);
18915c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {
1903af43ba4SHou Tao 		err = bpf_fd_htab_map_update_elem(map, map_file, key, value,
19115c14a3dSBrian Vazquez 						  flags);
19215c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
19315c14a3dSBrian Vazquez 		/* rcu_read_lock() is not needed */
19415c14a3dSBrian Vazquez 		err = bpf_fd_reuseport_array_update_elem(map, key, value,
19515c14a3dSBrian Vazquez 							 flags);
19615c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
1979330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_STACK ||
1989330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) {
19915c14a3dSBrian Vazquez 		err = map->ops->map_push_elem(map, value, flags);
20015c14a3dSBrian Vazquez 	} else {
20115c14a3dSBrian Vazquez 		rcu_read_lock();
20215c14a3dSBrian Vazquez 		err = map->ops->map_update_elem(map, key, value, flags);
20315c14a3dSBrian Vazquez 		rcu_read_unlock();
20415c14a3dSBrian Vazquez 	}
205b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
20615c14a3dSBrian Vazquez 
20715c14a3dSBrian Vazquez 	return err;
20815c14a3dSBrian Vazquez }
20915c14a3dSBrian Vazquez 
21015c14a3dSBrian Vazquez static int bpf_map_copy_value(struct bpf_map *map, void *key, void *value,
21115c14a3dSBrian Vazquez 			      __u64 flags)
21215c14a3dSBrian Vazquez {
21315c14a3dSBrian Vazquez 	void *ptr;
21415c14a3dSBrian Vazquez 	int err;
21515c14a3dSBrian Vazquez 
2169d03ebc7SStanislav Fomichev 	if (bpf_map_is_offloaded(map))
217cb4d03abSBrian Vazquez 		return bpf_map_offload_lookup_elem(map, key, value);
21815c14a3dSBrian Vazquez 
219b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
22015c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
22115c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
22215c14a3dSBrian Vazquez 		err = bpf_percpu_hash_copy(map, key, value);
22315c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
22415c14a3dSBrian Vazquez 		err = bpf_percpu_array_copy(map, key, value);
22515c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
22615c14a3dSBrian Vazquez 		err = bpf_percpu_cgroup_storage_copy(map, key, value);
22715c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) {
22815c14a3dSBrian Vazquez 		err = bpf_stackmap_copy(map, key, value);
22915c14a3dSBrian Vazquez 	} else if (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map)) {
23015c14a3dSBrian Vazquez 		err = bpf_fd_array_map_lookup_elem(map, key, value);
23115c14a3dSBrian Vazquez 	} else if (IS_FD_HASH(map)) {
23215c14a3dSBrian Vazquez 		err = bpf_fd_htab_map_lookup_elem(map, key, value);
23315c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
23415c14a3dSBrian Vazquez 		err = bpf_fd_reuseport_array_lookup_elem(map, key, value);
23515c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
2369330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_STACK ||
2379330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) {
23815c14a3dSBrian Vazquez 		err = map->ops->map_peek_elem(map, value);
23915c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
24015c14a3dSBrian Vazquez 		/* struct_ops map requires directly updating "value" */
24115c14a3dSBrian Vazquez 		err = bpf_struct_ops_map_sys_lookup_elem(map, key, value);
24215c14a3dSBrian Vazquez 	} else {
24315c14a3dSBrian Vazquez 		rcu_read_lock();
24415c14a3dSBrian Vazquez 		if (map->ops->map_lookup_elem_sys_only)
24515c14a3dSBrian Vazquez 			ptr = map->ops->map_lookup_elem_sys_only(map, key);
24615c14a3dSBrian Vazquez 		else
24715c14a3dSBrian Vazquez 			ptr = map->ops->map_lookup_elem(map, key);
24815c14a3dSBrian Vazquez 		if (IS_ERR(ptr)) {
24915c14a3dSBrian Vazquez 			err = PTR_ERR(ptr);
25015c14a3dSBrian Vazquez 		} else if (!ptr) {
25115c14a3dSBrian Vazquez 			err = -ENOENT;
25215c14a3dSBrian Vazquez 		} else {
25315c14a3dSBrian Vazquez 			err = 0;
25415c14a3dSBrian Vazquez 			if (flags & BPF_F_LOCK)
25515c14a3dSBrian Vazquez 				/* lock 'ptr' and copy everything but lock */
25615c14a3dSBrian Vazquez 				copy_map_value_locked(map, value, ptr, true);
25715c14a3dSBrian Vazquez 			else
25815c14a3dSBrian Vazquez 				copy_map_value(map, value, ptr);
25968134668SAlexei Starovoitov 			/* mask lock and timer, since value wasn't zero inited */
26068134668SAlexei Starovoitov 			check_and_init_map_value(map, value);
26115c14a3dSBrian Vazquez 		}
26215c14a3dSBrian Vazquez 		rcu_read_unlock();
26315c14a3dSBrian Vazquez 	}
26415c14a3dSBrian Vazquez 
265b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
26615c14a3dSBrian Vazquez 
26715c14a3dSBrian Vazquez 	return err;
26815c14a3dSBrian Vazquez }
26915c14a3dSBrian Vazquez 
270d5299b67SRoman Gushchin /* Please, do not use this function outside from the map creation path
271d5299b67SRoman Gushchin  * (e.g. in map update path) without taking care of setting the active
272d5299b67SRoman Gushchin  * memory cgroup (see at bpf_map_kmalloc_node() for example).
273d5299b67SRoman Gushchin  */
274196e8ca7SDaniel Borkmann static void *__bpf_map_area_alloc(u64 size, int numa_node, bool mmapable)
275d407bd25SDaniel Borkmann {
276f01a7dbeSMartynas Pumputis 	/* We really just want to fail instead of triggering OOM killer
277f01a7dbeSMartynas Pumputis 	 * under memory pressure, therefore we set __GFP_NORETRY to kmalloc,
278f01a7dbeSMartynas Pumputis 	 * which is used for lower order allocation requests.
279f01a7dbeSMartynas Pumputis 	 *
280f01a7dbeSMartynas Pumputis 	 * It has been observed that higher order allocation requests done by
281f01a7dbeSMartynas Pumputis 	 * vmalloc with __GFP_NORETRY being set might fail due to not trying
282f01a7dbeSMartynas Pumputis 	 * to reclaim memory from the page cache, thus we set
283f01a7dbeSMartynas Pumputis 	 * __GFP_RETRY_MAYFAIL to avoid such situations.
284d407bd25SDaniel Borkmann 	 */
285f01a7dbeSMartynas Pumputis 
286ee53cbfbSYafang Shao 	gfp_t gfp = bpf_memcg_flags(__GFP_NOWARN | __GFP_ZERO);
287041de93fSChristoph Hellwig 	unsigned int flags = 0;
288041de93fSChristoph Hellwig 	unsigned long align = 1;
289d407bd25SDaniel Borkmann 	void *area;
290d407bd25SDaniel Borkmann 
291196e8ca7SDaniel Borkmann 	if (size >= SIZE_MAX)
292196e8ca7SDaniel Borkmann 		return NULL;
293196e8ca7SDaniel Borkmann 
294fc970227SAndrii Nakryiko 	/* kmalloc()'ed memory can't be mmap()'ed */
295041de93fSChristoph Hellwig 	if (mmapable) {
296041de93fSChristoph Hellwig 		BUG_ON(!PAGE_ALIGNED(size));
297041de93fSChristoph Hellwig 		align = SHMLBA;
298041de93fSChristoph Hellwig 		flags = VM_USERMAP;
299041de93fSChristoph Hellwig 	} else if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
300041de93fSChristoph Hellwig 		area = kmalloc_node(size, gfp | GFP_USER | __GFP_NORETRY,
301f01a7dbeSMartynas Pumputis 				    numa_node);
302d407bd25SDaniel Borkmann 		if (area != NULL)
303d407bd25SDaniel Borkmann 			return area;
304d407bd25SDaniel Borkmann 	}
305041de93fSChristoph Hellwig 
306041de93fSChristoph Hellwig 	return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
307041de93fSChristoph Hellwig 			gfp | GFP_KERNEL | __GFP_RETRY_MAYFAIL, PAGE_KERNEL,
308041de93fSChristoph Hellwig 			flags, numa_node, __builtin_return_address(0));
309d407bd25SDaniel Borkmann }
310d407bd25SDaniel Borkmann 
311196e8ca7SDaniel Borkmann void *bpf_map_area_alloc(u64 size, int numa_node)
312fc970227SAndrii Nakryiko {
313fc970227SAndrii Nakryiko 	return __bpf_map_area_alloc(size, numa_node, false);
314fc970227SAndrii Nakryiko }
315fc970227SAndrii Nakryiko 
316196e8ca7SDaniel Borkmann void *bpf_map_area_mmapable_alloc(u64 size, int numa_node)
317fc970227SAndrii Nakryiko {
318fc970227SAndrii Nakryiko 	return __bpf_map_area_alloc(size, numa_node, true);
319fc970227SAndrii Nakryiko }
320fc970227SAndrii Nakryiko 
321d407bd25SDaniel Borkmann void bpf_map_area_free(void *area)
322d407bd25SDaniel Borkmann {
323d407bd25SDaniel Borkmann 	kvfree(area);
324d407bd25SDaniel Borkmann }
325d407bd25SDaniel Borkmann 
326be70bcd5SDaniel Borkmann static u32 bpf_map_flags_retain_permanent(u32 flags)
327be70bcd5SDaniel Borkmann {
328be70bcd5SDaniel Borkmann 	/* Some map creation flags are not tied to the map object but
329be70bcd5SDaniel Borkmann 	 * rather to the map fd instead, so they have no meaning upon
330be70bcd5SDaniel Borkmann 	 * map object inspection since multiple file descriptors with
331be70bcd5SDaniel Borkmann 	 * different (access) properties can exist here. Thus, given
332be70bcd5SDaniel Borkmann 	 * this has zero meaning for the map itself, lets clear these
333be70bcd5SDaniel Borkmann 	 * from here.
334be70bcd5SDaniel Borkmann 	 */
335be70bcd5SDaniel Borkmann 	return flags & ~(BPF_F_RDONLY | BPF_F_WRONLY);
336be70bcd5SDaniel Borkmann }
337be70bcd5SDaniel Borkmann 
338bd475643SJakub Kicinski void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr)
339bd475643SJakub Kicinski {
340bd475643SJakub Kicinski 	map->map_type = attr->map_type;
341bd475643SJakub Kicinski 	map->key_size = attr->key_size;
342bd475643SJakub Kicinski 	map->value_size = attr->value_size;
343bd475643SJakub Kicinski 	map->max_entries = attr->max_entries;
344be70bcd5SDaniel Borkmann 	map->map_flags = bpf_map_flags_retain_permanent(attr->map_flags);
345bd475643SJakub Kicinski 	map->numa_node = bpf_map_attr_numa_node(attr);
3469330986cSJoanne Koong 	map->map_extra = attr->map_extra;
347bd475643SJakub Kicinski }
348bd475643SJakub Kicinski 
349f3f1c054SMartin KaFai Lau static int bpf_map_alloc_id(struct bpf_map *map)
350f3f1c054SMartin KaFai Lau {
351f3f1c054SMartin KaFai Lau 	int id;
352f3f1c054SMartin KaFai Lau 
353b76354cdSShaohua Li 	idr_preload(GFP_KERNEL);
354f3f1c054SMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
355f3f1c054SMartin KaFai Lau 	id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC);
356f3f1c054SMartin KaFai Lau 	if (id > 0)
357f3f1c054SMartin KaFai Lau 		map->id = id;
358f3f1c054SMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
359b76354cdSShaohua Li 	idr_preload_end();
360f3f1c054SMartin KaFai Lau 
361f3f1c054SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
362f3f1c054SMartin KaFai Lau 		return -ENOSPC;
363f3f1c054SMartin KaFai Lau 
364f3f1c054SMartin KaFai Lau 	return id > 0 ? 0 : id;
365f3f1c054SMartin KaFai Lau }
366f3f1c054SMartin KaFai Lau 
367158e5e9eSTobias Klauser void bpf_map_free_id(struct bpf_map *map)
368f3f1c054SMartin KaFai Lau {
369930651a7SEric Dumazet 	unsigned long flags;
370930651a7SEric Dumazet 
371a3884572SJakub Kicinski 	/* Offloaded maps are removed from the IDR store when their device
372a3884572SJakub Kicinski 	 * disappears - even if someone holds an fd to them they are unusable,
373a3884572SJakub Kicinski 	 * the memory is gone, all ops will fail; they are simply waiting for
374a3884572SJakub Kicinski 	 * refcnt to drop to be freed.
375a3884572SJakub Kicinski 	 */
376a3884572SJakub Kicinski 	if (!map->id)
377a3884572SJakub Kicinski 		return;
378a3884572SJakub Kicinski 
379930651a7SEric Dumazet 	spin_lock_irqsave(&map_idr_lock, flags);
380bd5f5f4eSMartin KaFai Lau 
381f3f1c054SMartin KaFai Lau 	idr_remove(&map_idr, map->id);
382a3884572SJakub Kicinski 	map->id = 0;
383bd5f5f4eSMartin KaFai Lau 
384930651a7SEric Dumazet 	spin_unlock_irqrestore(&map_idr_lock, flags);
385f3f1c054SMartin KaFai Lau }
386f3f1c054SMartin KaFai Lau 
38748edc1f7SRoman Gushchin #ifdef CONFIG_MEMCG_KMEM
38848edc1f7SRoman Gushchin static void bpf_map_save_memcg(struct bpf_map *map)
38948edc1f7SRoman Gushchin {
3904201d9abSRoman Gushchin 	/* Currently if a map is created by a process belonging to the root
3914201d9abSRoman Gushchin 	 * memory cgroup, get_obj_cgroup_from_current() will return NULL.
3924201d9abSRoman Gushchin 	 * So we have to check map->objcg for being NULL each time it's
3934201d9abSRoman Gushchin 	 * being used.
3944201d9abSRoman Gushchin 	 */
395ee53cbfbSYafang Shao 	if (memcg_bpf_enabled())
3964201d9abSRoman Gushchin 		map->objcg = get_obj_cgroup_from_current();
39748edc1f7SRoman Gushchin }
39848edc1f7SRoman Gushchin 
39948edc1f7SRoman Gushchin static void bpf_map_release_memcg(struct bpf_map *map)
40048edc1f7SRoman Gushchin {
4014201d9abSRoman Gushchin 	if (map->objcg)
4024201d9abSRoman Gushchin 		obj_cgroup_put(map->objcg);
4034201d9abSRoman Gushchin }
4044201d9abSRoman Gushchin 
4054201d9abSRoman Gushchin static struct mem_cgroup *bpf_map_get_memcg(const struct bpf_map *map)
4064201d9abSRoman Gushchin {
4074201d9abSRoman Gushchin 	if (map->objcg)
4084201d9abSRoman Gushchin 		return get_mem_cgroup_from_objcg(map->objcg);
4094201d9abSRoman Gushchin 
4104201d9abSRoman Gushchin 	return root_mem_cgroup;
41148edc1f7SRoman Gushchin }
41248edc1f7SRoman Gushchin 
41348edc1f7SRoman Gushchin void *bpf_map_kmalloc_node(const struct bpf_map *map, size_t size, gfp_t flags,
41448edc1f7SRoman Gushchin 			   int node)
41548edc1f7SRoman Gushchin {
4164201d9abSRoman Gushchin 	struct mem_cgroup *memcg, *old_memcg;
41748edc1f7SRoman Gushchin 	void *ptr;
41848edc1f7SRoman Gushchin 
4194201d9abSRoman Gushchin 	memcg = bpf_map_get_memcg(map);
4204201d9abSRoman Gushchin 	old_memcg = set_active_memcg(memcg);
42148edc1f7SRoman Gushchin 	ptr = kmalloc_node(size, flags | __GFP_ACCOUNT, node);
42248edc1f7SRoman Gushchin 	set_active_memcg(old_memcg);
4234201d9abSRoman Gushchin 	mem_cgroup_put(memcg);
42448edc1f7SRoman Gushchin 
42548edc1f7SRoman Gushchin 	return ptr;
42648edc1f7SRoman Gushchin }
42748edc1f7SRoman Gushchin 
42848edc1f7SRoman Gushchin void *bpf_map_kzalloc(const struct bpf_map *map, size_t size, gfp_t flags)
42948edc1f7SRoman Gushchin {
4304201d9abSRoman Gushchin 	struct mem_cgroup *memcg, *old_memcg;
43148edc1f7SRoman Gushchin 	void *ptr;
43248edc1f7SRoman Gushchin 
4334201d9abSRoman Gushchin 	memcg = bpf_map_get_memcg(map);
4344201d9abSRoman Gushchin 	old_memcg = set_active_memcg(memcg);
43548edc1f7SRoman Gushchin 	ptr = kzalloc(size, flags | __GFP_ACCOUNT);
43648edc1f7SRoman Gushchin 	set_active_memcg(old_memcg);
4374201d9abSRoman Gushchin 	mem_cgroup_put(memcg);
43848edc1f7SRoman Gushchin 
43948edc1f7SRoman Gushchin 	return ptr;
44048edc1f7SRoman Gushchin }
44148edc1f7SRoman Gushchin 
442ddef81b5SYafang Shao void *bpf_map_kvcalloc(struct bpf_map *map, size_t n, size_t size,
443ddef81b5SYafang Shao 		       gfp_t flags)
444ddef81b5SYafang Shao {
445ddef81b5SYafang Shao 	struct mem_cgroup *memcg, *old_memcg;
446ddef81b5SYafang Shao 	void *ptr;
447ddef81b5SYafang Shao 
448ddef81b5SYafang Shao 	memcg = bpf_map_get_memcg(map);
449ddef81b5SYafang Shao 	old_memcg = set_active_memcg(memcg);
450ddef81b5SYafang Shao 	ptr = kvcalloc(n, size, flags | __GFP_ACCOUNT);
451ddef81b5SYafang Shao 	set_active_memcg(old_memcg);
452ddef81b5SYafang Shao 	mem_cgroup_put(memcg);
453ddef81b5SYafang Shao 
454ddef81b5SYafang Shao 	return ptr;
455ddef81b5SYafang Shao }
456ddef81b5SYafang Shao 
45748edc1f7SRoman Gushchin void __percpu *bpf_map_alloc_percpu(const struct bpf_map *map, size_t size,
45848edc1f7SRoman Gushchin 				    size_t align, gfp_t flags)
45948edc1f7SRoman Gushchin {
4604201d9abSRoman Gushchin 	struct mem_cgroup *memcg, *old_memcg;
46148edc1f7SRoman Gushchin 	void __percpu *ptr;
46248edc1f7SRoman Gushchin 
4634201d9abSRoman Gushchin 	memcg = bpf_map_get_memcg(map);
4644201d9abSRoman Gushchin 	old_memcg = set_active_memcg(memcg);
46548edc1f7SRoman Gushchin 	ptr = __alloc_percpu_gfp(size, align, flags | __GFP_ACCOUNT);
46648edc1f7SRoman Gushchin 	set_active_memcg(old_memcg);
4674201d9abSRoman Gushchin 	mem_cgroup_put(memcg);
46848edc1f7SRoman Gushchin 
46948edc1f7SRoman Gushchin 	return ptr;
47048edc1f7SRoman Gushchin }
47148edc1f7SRoman Gushchin 
47248edc1f7SRoman Gushchin #else
47348edc1f7SRoman Gushchin static void bpf_map_save_memcg(struct bpf_map *map)
47448edc1f7SRoman Gushchin {
47548edc1f7SRoman Gushchin }
47648edc1f7SRoman Gushchin 
47748edc1f7SRoman Gushchin static void bpf_map_release_memcg(struct bpf_map *map)
47848edc1f7SRoman Gushchin {
47948edc1f7SRoman Gushchin }
48048edc1f7SRoman Gushchin #endif
48148edc1f7SRoman Gushchin 
482aa3496acSKumar Kartikeya Dwivedi static int btf_field_cmp(const void *a, const void *b)
48361df10c7SKumar Kartikeya Dwivedi {
484aa3496acSKumar Kartikeya Dwivedi 	const struct btf_field *f1 = a, *f2 = b;
48561df10c7SKumar Kartikeya Dwivedi 
486aa3496acSKumar Kartikeya Dwivedi 	if (f1->offset < f2->offset)
48761df10c7SKumar Kartikeya Dwivedi 		return -1;
488aa3496acSKumar Kartikeya Dwivedi 	else if (f1->offset > f2->offset)
48961df10c7SKumar Kartikeya Dwivedi 		return 1;
49061df10c7SKumar Kartikeya Dwivedi 	return 0;
49161df10c7SKumar Kartikeya Dwivedi }
49261df10c7SKumar Kartikeya Dwivedi 
493aa3496acSKumar Kartikeya Dwivedi struct btf_field *btf_record_find(const struct btf_record *rec, u32 offset,
49474843b57SDave Marchevsky 				  u32 field_mask)
49561df10c7SKumar Kartikeya Dwivedi {
496aa3496acSKumar Kartikeya Dwivedi 	struct btf_field *field;
49761df10c7SKumar Kartikeya Dwivedi 
49874843b57SDave Marchevsky 	if (IS_ERR_OR_NULL(rec) || !(rec->field_mask & field_mask))
49961df10c7SKumar Kartikeya Dwivedi 		return NULL;
500aa3496acSKumar Kartikeya Dwivedi 	field = bsearch(&offset, rec->fields, rec->cnt, sizeof(rec->fields[0]), btf_field_cmp);
50174843b57SDave Marchevsky 	if (!field || !(field->type & field_mask))
502aa3496acSKumar Kartikeya Dwivedi 		return NULL;
503aa3496acSKumar Kartikeya Dwivedi 	return field;
50461df10c7SKumar Kartikeya Dwivedi }
50561df10c7SKumar Kartikeya Dwivedi 
506aa3496acSKumar Kartikeya Dwivedi void btf_record_free(struct btf_record *rec)
50761df10c7SKumar Kartikeya Dwivedi {
50861df10c7SKumar Kartikeya Dwivedi 	int i;
50961df10c7SKumar Kartikeya Dwivedi 
510aa3496acSKumar Kartikeya Dwivedi 	if (IS_ERR_OR_NULL(rec))
51161df10c7SKumar Kartikeya Dwivedi 		return;
512aa3496acSKumar Kartikeya Dwivedi 	for (i = 0; i < rec->cnt; i++) {
513aa3496acSKumar Kartikeya Dwivedi 		switch (rec->fields[i].type) {
514aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_UNREF:
515aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_REF:
51655db92f4SYonghong Song 		case BPF_KPTR_PERCPU:
517aa3496acSKumar Kartikeya Dwivedi 			if (rec->fields[i].kptr.module)
518aa3496acSKumar Kartikeya Dwivedi 				module_put(rec->fields[i].kptr.module);
519aa3496acSKumar Kartikeya Dwivedi 			btf_put(rec->fields[i].kptr.btf);
520aa3496acSKumar Kartikeya Dwivedi 			break;
521f0c5941fSKumar Kartikeya Dwivedi 		case BPF_LIST_HEAD:
5228ffa5cc1SKumar Kartikeya Dwivedi 		case BPF_LIST_NODE:
5239c395c1bSDave Marchevsky 		case BPF_RB_ROOT:
5249c395c1bSDave Marchevsky 		case BPF_RB_NODE:
5259c395c1bSDave Marchevsky 		case BPF_SPIN_LOCK:
5269c395c1bSDave Marchevsky 		case BPF_TIMER:
527d54730b5SDave Marchevsky 		case BPF_REFCOUNT:
5289c395c1bSDave Marchevsky 			/* Nothing to release */
529f0c5941fSKumar Kartikeya Dwivedi 			break;
530aa3496acSKumar Kartikeya Dwivedi 		default:
531aa3496acSKumar Kartikeya Dwivedi 			WARN_ON_ONCE(1);
53214a324f6SKumar Kartikeya Dwivedi 			continue;
53314a324f6SKumar Kartikeya Dwivedi 		}
534aa3496acSKumar Kartikeya Dwivedi 	}
535aa3496acSKumar Kartikeya Dwivedi 	kfree(rec);
536aa3496acSKumar Kartikeya Dwivedi }
537aa3496acSKumar Kartikeya Dwivedi 
538aa3496acSKumar Kartikeya Dwivedi void bpf_map_free_record(struct bpf_map *map)
539aa3496acSKumar Kartikeya Dwivedi {
540aa3496acSKumar Kartikeya Dwivedi 	btf_record_free(map->record);
541aa3496acSKumar Kartikeya Dwivedi 	map->record = NULL;
542aa3496acSKumar Kartikeya Dwivedi }
543aa3496acSKumar Kartikeya Dwivedi 
544aa3496acSKumar Kartikeya Dwivedi struct btf_record *btf_record_dup(const struct btf_record *rec)
545aa3496acSKumar Kartikeya Dwivedi {
546aa3496acSKumar Kartikeya Dwivedi 	const struct btf_field *fields;
547aa3496acSKumar Kartikeya Dwivedi 	struct btf_record *new_rec;
548aa3496acSKumar Kartikeya Dwivedi 	int ret, size, i;
549aa3496acSKumar Kartikeya Dwivedi 
550aa3496acSKumar Kartikeya Dwivedi 	if (IS_ERR_OR_NULL(rec))
551aa3496acSKumar Kartikeya Dwivedi 		return NULL;
552aa3496acSKumar Kartikeya Dwivedi 	size = offsetof(struct btf_record, fields[rec->cnt]);
553aa3496acSKumar Kartikeya Dwivedi 	new_rec = kmemdup(rec, size, GFP_KERNEL | __GFP_NOWARN);
554aa3496acSKumar Kartikeya Dwivedi 	if (!new_rec)
555aa3496acSKumar Kartikeya Dwivedi 		return ERR_PTR(-ENOMEM);
556aa3496acSKumar Kartikeya Dwivedi 	/* Do a deep copy of the btf_record */
557aa3496acSKumar Kartikeya Dwivedi 	fields = rec->fields;
558aa3496acSKumar Kartikeya Dwivedi 	new_rec->cnt = 0;
559aa3496acSKumar Kartikeya Dwivedi 	for (i = 0; i < rec->cnt; i++) {
560aa3496acSKumar Kartikeya Dwivedi 		switch (fields[i].type) {
561aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_UNREF:
562aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_REF:
56355db92f4SYonghong Song 		case BPF_KPTR_PERCPU:
564aa3496acSKumar Kartikeya Dwivedi 			btf_get(fields[i].kptr.btf);
565aa3496acSKumar Kartikeya Dwivedi 			if (fields[i].kptr.module && !try_module_get(fields[i].kptr.module)) {
566aa3496acSKumar Kartikeya Dwivedi 				ret = -ENXIO;
567aa3496acSKumar Kartikeya Dwivedi 				goto free;
568aa3496acSKumar Kartikeya Dwivedi 			}
569aa3496acSKumar Kartikeya Dwivedi 			break;
570f0c5941fSKumar Kartikeya Dwivedi 		case BPF_LIST_HEAD:
5718ffa5cc1SKumar Kartikeya Dwivedi 		case BPF_LIST_NODE:
5729c395c1bSDave Marchevsky 		case BPF_RB_ROOT:
5739c395c1bSDave Marchevsky 		case BPF_RB_NODE:
5749c395c1bSDave Marchevsky 		case BPF_SPIN_LOCK:
5759c395c1bSDave Marchevsky 		case BPF_TIMER:
576d54730b5SDave Marchevsky 		case BPF_REFCOUNT:
5779c395c1bSDave Marchevsky 			/* Nothing to acquire */
578f0c5941fSKumar Kartikeya Dwivedi 			break;
579aa3496acSKumar Kartikeya Dwivedi 		default:
580aa3496acSKumar Kartikeya Dwivedi 			ret = -EFAULT;
581aa3496acSKumar Kartikeya Dwivedi 			WARN_ON_ONCE(1);
582aa3496acSKumar Kartikeya Dwivedi 			goto free;
583aa3496acSKumar Kartikeya Dwivedi 		}
584aa3496acSKumar Kartikeya Dwivedi 		new_rec->cnt++;
585aa3496acSKumar Kartikeya Dwivedi 	}
586aa3496acSKumar Kartikeya Dwivedi 	return new_rec;
587aa3496acSKumar Kartikeya Dwivedi free:
588aa3496acSKumar Kartikeya Dwivedi 	btf_record_free(new_rec);
589aa3496acSKumar Kartikeya Dwivedi 	return ERR_PTR(ret);
590aa3496acSKumar Kartikeya Dwivedi }
591aa3496acSKumar Kartikeya Dwivedi 
592aa3496acSKumar Kartikeya Dwivedi bool btf_record_equal(const struct btf_record *rec_a, const struct btf_record *rec_b)
593aa3496acSKumar Kartikeya Dwivedi {
594aa3496acSKumar Kartikeya Dwivedi 	bool a_has_fields = !IS_ERR_OR_NULL(rec_a), b_has_fields = !IS_ERR_OR_NULL(rec_b);
595aa3496acSKumar Kartikeya Dwivedi 	int size;
596aa3496acSKumar Kartikeya Dwivedi 
597aa3496acSKumar Kartikeya Dwivedi 	if (!a_has_fields && !b_has_fields)
598aa3496acSKumar Kartikeya Dwivedi 		return true;
599aa3496acSKumar Kartikeya Dwivedi 	if (a_has_fields != b_has_fields)
600aa3496acSKumar Kartikeya Dwivedi 		return false;
601aa3496acSKumar Kartikeya Dwivedi 	if (rec_a->cnt != rec_b->cnt)
602aa3496acSKumar Kartikeya Dwivedi 		return false;
603aa3496acSKumar Kartikeya Dwivedi 	size = offsetof(struct btf_record, fields[rec_a->cnt]);
604c22dfdd2SKumar Kartikeya Dwivedi 	/* btf_parse_fields uses kzalloc to allocate a btf_record, so unused
605c22dfdd2SKumar Kartikeya Dwivedi 	 * members are zeroed out. So memcmp is safe to do without worrying
606c22dfdd2SKumar Kartikeya Dwivedi 	 * about padding/unused fields.
607c22dfdd2SKumar Kartikeya Dwivedi 	 *
608c22dfdd2SKumar Kartikeya Dwivedi 	 * While spin_lock, timer, and kptr have no relation to map BTF,
609c22dfdd2SKumar Kartikeya Dwivedi 	 * list_head metadata is specific to map BTF, the btf and value_rec
610c22dfdd2SKumar Kartikeya Dwivedi 	 * members in particular. btf is the map BTF, while value_rec points to
611c22dfdd2SKumar Kartikeya Dwivedi 	 * btf_record in that map BTF.
612c22dfdd2SKumar Kartikeya Dwivedi 	 *
613c22dfdd2SKumar Kartikeya Dwivedi 	 * So while by default, we don't rely on the map BTF (which the records
614c22dfdd2SKumar Kartikeya Dwivedi 	 * were parsed from) matching for both records, which is not backwards
615c22dfdd2SKumar Kartikeya Dwivedi 	 * compatible, in case list_head is part of it, we implicitly rely on
616c22dfdd2SKumar Kartikeya Dwivedi 	 * that by way of depending on memcmp succeeding for it.
617c22dfdd2SKumar Kartikeya Dwivedi 	 */
618aa3496acSKumar Kartikeya Dwivedi 	return !memcmp(rec_a, rec_b, size);
619aa3496acSKumar Kartikeya Dwivedi }
620aa3496acSKumar Kartikeya Dwivedi 
621db559117SKumar Kartikeya Dwivedi void bpf_obj_free_timer(const struct btf_record *rec, void *obj)
622db559117SKumar Kartikeya Dwivedi {
623db559117SKumar Kartikeya Dwivedi 	if (WARN_ON_ONCE(!btf_record_has_field(rec, BPF_TIMER)))
624db559117SKumar Kartikeya Dwivedi 		return;
625db559117SKumar Kartikeya Dwivedi 	bpf_timer_cancel_and_free(obj + rec->timer_off);
626db559117SKumar Kartikeya Dwivedi }
627db559117SKumar Kartikeya Dwivedi 
628aa3496acSKumar Kartikeya Dwivedi void bpf_obj_free_fields(const struct btf_record *rec, void *obj)
629aa3496acSKumar Kartikeya Dwivedi {
630aa3496acSKumar Kartikeya Dwivedi 	const struct btf_field *fields;
631aa3496acSKumar Kartikeya Dwivedi 	int i;
632aa3496acSKumar Kartikeya Dwivedi 
633aa3496acSKumar Kartikeya Dwivedi 	if (IS_ERR_OR_NULL(rec))
634aa3496acSKumar Kartikeya Dwivedi 		return;
635aa3496acSKumar Kartikeya Dwivedi 	fields = rec->fields;
636aa3496acSKumar Kartikeya Dwivedi 	for (i = 0; i < rec->cnt; i++) {
637c8e18754SDave Marchevsky 		struct btf_struct_meta *pointee_struct_meta;
638aa3496acSKumar Kartikeya Dwivedi 		const struct btf_field *field = &fields[i];
639aa3496acSKumar Kartikeya Dwivedi 		void *field_ptr = obj + field->offset;
640c8e18754SDave Marchevsky 		void *xchgd_field;
641aa3496acSKumar Kartikeya Dwivedi 
642aa3496acSKumar Kartikeya Dwivedi 		switch (fields[i].type) {
643db559117SKumar Kartikeya Dwivedi 		case BPF_SPIN_LOCK:
644db559117SKumar Kartikeya Dwivedi 			break;
645db559117SKumar Kartikeya Dwivedi 		case BPF_TIMER:
646db559117SKumar Kartikeya Dwivedi 			bpf_timer_cancel_and_free(field_ptr);
647db559117SKumar Kartikeya Dwivedi 			break;
648aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_UNREF:
649aa3496acSKumar Kartikeya Dwivedi 			WRITE_ONCE(*(u64 *)field_ptr, 0);
650aa3496acSKumar Kartikeya Dwivedi 			break;
651aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_REF:
65255db92f4SYonghong Song 		case BPF_KPTR_PERCPU:
653c8e18754SDave Marchevsky 			xchgd_field = (void *)xchg((unsigned long *)field_ptr, 0);
6541431d0b5SDavid Vernet 			if (!xchgd_field)
6551431d0b5SDavid Vernet 				break;
6561431d0b5SDavid Vernet 
657c8e18754SDave Marchevsky 			if (!btf_is_kernel(field->kptr.btf)) {
658c8e18754SDave Marchevsky 				pointee_struct_meta = btf_find_struct_meta(field->kptr.btf,
659c8e18754SDave Marchevsky 									   field->kptr.btf_id);
6609e36a204SDave Marchevsky 				migrate_disable();
6619e36a204SDave Marchevsky 				__bpf_obj_drop_impl(xchgd_field, pointee_struct_meta ?
662e383a459SHou Tao 								 pointee_struct_meta->record : NULL,
663e383a459SHou Tao 								 fields[i].type == BPF_KPTR_PERCPU);
6649e36a204SDave Marchevsky 				migrate_enable();
665c8e18754SDave Marchevsky 			} else {
666c8e18754SDave Marchevsky 				field->kptr.dtor(xchgd_field);
667c8e18754SDave Marchevsky 			}
668aa3496acSKumar Kartikeya Dwivedi 			break;
669f0c5941fSKumar Kartikeya Dwivedi 		case BPF_LIST_HEAD:
670f0c5941fSKumar Kartikeya Dwivedi 			if (WARN_ON_ONCE(rec->spin_lock_off < 0))
671f0c5941fSKumar Kartikeya Dwivedi 				continue;
672f0c5941fSKumar Kartikeya Dwivedi 			bpf_list_head_free(field, field_ptr, obj + rec->spin_lock_off);
673f0c5941fSKumar Kartikeya Dwivedi 			break;
6749c395c1bSDave Marchevsky 		case BPF_RB_ROOT:
6759c395c1bSDave Marchevsky 			if (WARN_ON_ONCE(rec->spin_lock_off < 0))
6769c395c1bSDave Marchevsky 				continue;
6779c395c1bSDave Marchevsky 			bpf_rb_root_free(field, field_ptr, obj + rec->spin_lock_off);
6789c395c1bSDave Marchevsky 			break;
6798ffa5cc1SKumar Kartikeya Dwivedi 		case BPF_LIST_NODE:
6809c395c1bSDave Marchevsky 		case BPF_RB_NODE:
681d54730b5SDave Marchevsky 		case BPF_REFCOUNT:
6828ffa5cc1SKumar Kartikeya Dwivedi 			break;
683aa3496acSKumar Kartikeya Dwivedi 		default:
684aa3496acSKumar Kartikeya Dwivedi 			WARN_ON_ONCE(1);
685aa3496acSKumar Kartikeya Dwivedi 			continue;
686aa3496acSKumar Kartikeya Dwivedi 		}
68714a324f6SKumar Kartikeya Dwivedi 	}
68814a324f6SKumar Kartikeya Dwivedi }
68914a324f6SKumar Kartikeya Dwivedi 
69099c55f7dSAlexei Starovoitov /* called from workqueue */
69199c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work)
69299c55f7dSAlexei Starovoitov {
69399c55f7dSAlexei Starovoitov 	struct bpf_map *map = container_of(work, struct bpf_map, work);
694d7f5ef65SKumar Kartikeya Dwivedi 	struct btf_record *rec = map->record;
69559e5791fSYonghong Song 	struct btf *btf = map->btf;
69699c55f7dSAlexei Starovoitov 
697afdb09c7SChenbo Feng 	security_bpf_map_free(map);
69848edc1f7SRoman Gushchin 	bpf_map_release_memcg(map);
699d7f5ef65SKumar Kartikeya Dwivedi 	/* implementation dependent freeing */
70099c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
701cd2a8079SDave Marchevsky 	/* Delay freeing of btf_record for maps, as map_free
702d7f5ef65SKumar Kartikeya Dwivedi 	 * callback usually needs access to them. It is better to do it here
703d7f5ef65SKumar Kartikeya Dwivedi 	 * than require each callback to do the free itself manually.
704d7f5ef65SKumar Kartikeya Dwivedi 	 *
705d7f5ef65SKumar Kartikeya Dwivedi 	 * Note that the btf_record stashed in map->inner_map_meta->record was
706d7f5ef65SKumar Kartikeya Dwivedi 	 * already freed using the map_free callback for map in map case which
707d7f5ef65SKumar Kartikeya Dwivedi 	 * eventually calls bpf_map_free_meta, since inner_map_meta is only a
708d7f5ef65SKumar Kartikeya Dwivedi 	 * template bpf_map struct used during verification.
709d7f5ef65SKumar Kartikeya Dwivedi 	 */
710d7f5ef65SKumar Kartikeya Dwivedi 	btf_record_free(rec);
71159e5791fSYonghong Song 	/* Delay freeing of btf for maps, as map_free callback may need
71259e5791fSYonghong Song 	 * struct_meta info which will be freed with btf_put().
71359e5791fSYonghong Song 	 */
71459e5791fSYonghong Song 	btf_put(btf);
71599c55f7dSAlexei Starovoitov }
71699c55f7dSAlexei Starovoitov 
717c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map)
718c9da161cSDaniel Borkmann {
7191e0bd5a0SAndrii Nakryiko 	if (atomic64_dec_and_test(&map->usercnt)) {
720ba6b8de4SJohn Fastabend 		if (map->ops->map_release_uref)
721ba6b8de4SJohn Fastabend 			map->ops->map_release_uref(map);
722c9da161cSDaniel Borkmann 	}
723c9da161cSDaniel Borkmann }
724c9da161cSDaniel Borkmann 
72587667336SHou Tao static void bpf_map_free_in_work(struct bpf_map *map)
72687667336SHou Tao {
72787667336SHou Tao 	INIT_WORK(&map->work, bpf_map_free_deferred);
72887667336SHou Tao 	/* Avoid spawning kworkers, since they all might contend
72987667336SHou Tao 	 * for the same mutex like slab_mutex.
73087667336SHou Tao 	 */
73187667336SHou Tao 	queue_work(system_unbound_wq, &map->work);
73287667336SHou Tao }
73387667336SHou Tao 
73487667336SHou Tao static void bpf_map_free_rcu_gp(struct rcu_head *rcu)
73587667336SHou Tao {
73687667336SHou Tao 	bpf_map_free_in_work(container_of(rcu, struct bpf_map, rcu));
73787667336SHou Tao }
73887667336SHou Tao 
73987667336SHou Tao static void bpf_map_free_mult_rcu_gp(struct rcu_head *rcu)
74087667336SHou Tao {
74187667336SHou Tao 	if (rcu_trace_implies_rcu_gp())
74287667336SHou Tao 		bpf_map_free_rcu_gp(rcu);
74387667336SHou Tao 	else
74487667336SHou Tao 		call_rcu(rcu, bpf_map_free_rcu_gp);
74587667336SHou Tao }
74687667336SHou Tao 
74799c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue
748158e5e9eSTobias Klauser  * (underlying map implementation ops->map_free() might sleep)
74999c55f7dSAlexei Starovoitov  */
750158e5e9eSTobias Klauser void bpf_map_put(struct bpf_map *map)
75199c55f7dSAlexei Starovoitov {
7521e0bd5a0SAndrii Nakryiko 	if (atomic64_dec_and_test(&map->refcnt)) {
75334ad5580SMartin KaFai Lau 		/* bpf_map_free_id() must be called first */
754158e5e9eSTobias Klauser 		bpf_map_free_id(map);
75587667336SHou Tao 
756af66bfd3SHou Tao 		WARN_ON_ONCE(atomic64_read(&map->sleepable_refcnt));
75787667336SHou Tao 		if (READ_ONCE(map->free_after_mult_rcu_gp))
75887667336SHou Tao 			call_rcu_tasks_trace(&map->rcu, bpf_map_free_mult_rcu_gp);
759af66bfd3SHou Tao 		else if (READ_ONCE(map->free_after_rcu_gp))
760af66bfd3SHou Tao 			call_rcu(&map->rcu, bpf_map_free_rcu_gp);
76187667336SHou Tao 		else
76287667336SHou Tao 			bpf_map_free_in_work(map);
76399c55f7dSAlexei Starovoitov 	}
76499c55f7dSAlexei Starovoitov }
765630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_put);
766bd5f5f4eSMartin KaFai Lau 
767c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map)
768c9da161cSDaniel Borkmann {
769c9da161cSDaniel Borkmann 	bpf_map_put_uref(map);
770c9da161cSDaniel Borkmann 	bpf_map_put(map);
771c9da161cSDaniel Borkmann }
772c9da161cSDaniel Borkmann 
77399c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp)
77499c55f7dSAlexei Starovoitov {
77561d1b6a4SDaniel Borkmann 	struct bpf_map *map = filp->private_data;
77661d1b6a4SDaniel Borkmann 
77761d1b6a4SDaniel Borkmann 	if (map->ops->map_release)
77861d1b6a4SDaniel Borkmann 		map->ops->map_release(map, filp);
77961d1b6a4SDaniel Borkmann 
78061d1b6a4SDaniel Borkmann 	bpf_map_put_with_uref(map);
78199c55f7dSAlexei Starovoitov 	return 0;
78299c55f7dSAlexei Starovoitov }
78399c55f7dSAlexei Starovoitov 
78487df15deSDaniel Borkmann static fmode_t map_get_sys_perms(struct bpf_map *map, struct fd f)
78587df15deSDaniel Borkmann {
78687df15deSDaniel Borkmann 	fmode_t mode = f.file->f_mode;
78787df15deSDaniel Borkmann 
78887df15deSDaniel Borkmann 	/* Our file permissions may have been overridden by global
78987df15deSDaniel Borkmann 	 * map permissions facing syscall side.
79087df15deSDaniel Borkmann 	 */
79187df15deSDaniel Borkmann 	if (READ_ONCE(map->frozen))
79287df15deSDaniel Borkmann 		mode &= ~FMODE_CAN_WRITE;
79387df15deSDaniel Borkmann 	return mode;
79487df15deSDaniel Borkmann }
79587df15deSDaniel Borkmann 
796f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
79790a5527dSYafang Shao /* Show the memory usage of a bpf map */
79890a5527dSYafang Shao static u64 bpf_map_memory_usage(const struct bpf_map *map)
79980ee81e0SRoman Gushchin {
80090a5527dSYafang Shao 	return map->ops->map_mem_usage(map);
80180ee81e0SRoman Gushchin }
80280ee81e0SRoman Gushchin 
803f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)
804f99bf205SDaniel Borkmann {
805f45d5b6cSToke Hoiland-Jorgensen 	struct bpf_map *map = filp->private_data;
8062beee5f5SDaniel Borkmann 	u32 type = 0, jited = 0;
80721116b70SDaniel Borkmann 
808f45d5b6cSToke Hoiland-Jorgensen 	if (map_type_contains_progs(map)) {
809f45d5b6cSToke Hoiland-Jorgensen 		spin_lock(&map->owner.lock);
810f45d5b6cSToke Hoiland-Jorgensen 		type  = map->owner.type;
811f45d5b6cSToke Hoiland-Jorgensen 		jited = map->owner.jited;
812f45d5b6cSToke Hoiland-Jorgensen 		spin_unlock(&map->owner.lock);
81321116b70SDaniel Borkmann 	}
814f99bf205SDaniel Borkmann 
815f99bf205SDaniel Borkmann 	seq_printf(m,
816f99bf205SDaniel Borkmann 		   "map_type:\t%u\n"
817f99bf205SDaniel Borkmann 		   "key_size:\t%u\n"
818f99bf205SDaniel Borkmann 		   "value_size:\t%u\n"
819322cea2fSDaniel Borkmann 		   "max_entries:\t%u\n"
82021116b70SDaniel Borkmann 		   "map_flags:\t%#x\n"
8219330986cSJoanne Koong 		   "map_extra:\t%#llx\n"
82290a5527dSYafang Shao 		   "memlock:\t%llu\n"
82387df15deSDaniel Borkmann 		   "map_id:\t%u\n"
82487df15deSDaniel Borkmann 		   "frozen:\t%u\n",
825f99bf205SDaniel Borkmann 		   map->map_type,
826f99bf205SDaniel Borkmann 		   map->key_size,
827f99bf205SDaniel Borkmann 		   map->value_size,
828322cea2fSDaniel Borkmann 		   map->max_entries,
82921116b70SDaniel Borkmann 		   map->map_flags,
8309330986cSJoanne Koong 		   (unsigned long long)map->map_extra,
83190a5527dSYafang Shao 		   bpf_map_memory_usage(map),
83287df15deSDaniel Borkmann 		   map->id,
83387df15deSDaniel Borkmann 		   READ_ONCE(map->frozen));
8342beee5f5SDaniel Borkmann 	if (type) {
8352beee5f5SDaniel Borkmann 		seq_printf(m, "owner_prog_type:\t%u\n", type);
8362beee5f5SDaniel Borkmann 		seq_printf(m, "owner_jited:\t%u\n", jited);
8379780c0abSDaniel Borkmann 	}
838f99bf205SDaniel Borkmann }
839f99bf205SDaniel Borkmann #endif
840f99bf205SDaniel Borkmann 
8416e71b04aSChenbo Feng static ssize_t bpf_dummy_read(struct file *filp, char __user *buf, size_t siz,
8426e71b04aSChenbo Feng 			      loff_t *ppos)
8436e71b04aSChenbo Feng {
8446e71b04aSChenbo Feng 	/* We need this handler such that alloc_file() enables
8456e71b04aSChenbo Feng 	 * f_mode with FMODE_CAN_READ.
8466e71b04aSChenbo Feng 	 */
8476e71b04aSChenbo Feng 	return -EINVAL;
8486e71b04aSChenbo Feng }
8496e71b04aSChenbo Feng 
8506e71b04aSChenbo Feng static ssize_t bpf_dummy_write(struct file *filp, const char __user *buf,
8516e71b04aSChenbo Feng 			       size_t siz, loff_t *ppos)
8526e71b04aSChenbo Feng {
8536e71b04aSChenbo Feng 	/* We need this handler such that alloc_file() enables
8546e71b04aSChenbo Feng 	 * f_mode with FMODE_CAN_WRITE.
8556e71b04aSChenbo Feng 	 */
8566e71b04aSChenbo Feng 	return -EINVAL;
8576e71b04aSChenbo Feng }
8586e71b04aSChenbo Feng 
859fc970227SAndrii Nakryiko /* called for any extra memory-mapped regions (except initial) */
860fc970227SAndrii Nakryiko static void bpf_map_mmap_open(struct vm_area_struct *vma)
861fc970227SAndrii Nakryiko {
862fc970227SAndrii Nakryiko 	struct bpf_map *map = vma->vm_file->private_data;
863fc970227SAndrii Nakryiko 
864353050beSDaniel Borkmann 	if (vma->vm_flags & VM_MAYWRITE)
865353050beSDaniel Borkmann 		bpf_map_write_active_inc(map);
866fc970227SAndrii Nakryiko }
867fc970227SAndrii Nakryiko 
868fc970227SAndrii Nakryiko /* called for all unmapped memory region (including initial) */
869fc970227SAndrii Nakryiko static void bpf_map_mmap_close(struct vm_area_struct *vma)
870fc970227SAndrii Nakryiko {
871fc970227SAndrii Nakryiko 	struct bpf_map *map = vma->vm_file->private_data;
872fc970227SAndrii Nakryiko 
873353050beSDaniel Borkmann 	if (vma->vm_flags & VM_MAYWRITE)
874353050beSDaniel Borkmann 		bpf_map_write_active_dec(map);
875fc970227SAndrii Nakryiko }
876fc970227SAndrii Nakryiko 
877fc970227SAndrii Nakryiko static const struct vm_operations_struct bpf_map_default_vmops = {
878fc970227SAndrii Nakryiko 	.open		= bpf_map_mmap_open,
879fc970227SAndrii Nakryiko 	.close		= bpf_map_mmap_close,
880fc970227SAndrii Nakryiko };
881fc970227SAndrii Nakryiko 
882fc970227SAndrii Nakryiko static int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma)
883fc970227SAndrii Nakryiko {
884fc970227SAndrii Nakryiko 	struct bpf_map *map = filp->private_data;
885fc970227SAndrii Nakryiko 	int err;
886fc970227SAndrii Nakryiko 
887db559117SKumar Kartikeya Dwivedi 	if (!map->ops->map_mmap || !IS_ERR_OR_NULL(map->record))
888fc970227SAndrii Nakryiko 		return -ENOTSUPP;
889fc970227SAndrii Nakryiko 
890fc970227SAndrii Nakryiko 	if (!(vma->vm_flags & VM_SHARED))
891fc970227SAndrii Nakryiko 		return -EINVAL;
892fc970227SAndrii Nakryiko 
893fc970227SAndrii Nakryiko 	mutex_lock(&map->freeze_mutex);
894fc970227SAndrii Nakryiko 
895dfeb376dSAndrii Nakryiko 	if (vma->vm_flags & VM_WRITE) {
896dfeb376dSAndrii Nakryiko 		if (map->frozen) {
897fc970227SAndrii Nakryiko 			err = -EPERM;
898fc970227SAndrii Nakryiko 			goto out;
899fc970227SAndrii Nakryiko 		}
900dfeb376dSAndrii Nakryiko 		/* map is meant to be read-only, so do not allow mapping as
901dfeb376dSAndrii Nakryiko 		 * writable, because it's possible to leak a writable page
902dfeb376dSAndrii Nakryiko 		 * reference and allows user-space to still modify it after
903dfeb376dSAndrii Nakryiko 		 * freezing, while verifier will assume contents do not change
904dfeb376dSAndrii Nakryiko 		 */
905dfeb376dSAndrii Nakryiko 		if (map->map_flags & BPF_F_RDONLY_PROG) {
906dfeb376dSAndrii Nakryiko 			err = -EACCES;
907dfeb376dSAndrii Nakryiko 			goto out;
908dfeb376dSAndrii Nakryiko 		}
909dfeb376dSAndrii Nakryiko 	}
910fc970227SAndrii Nakryiko 
911fc970227SAndrii Nakryiko 	/* set default open/close callbacks */
912fc970227SAndrii Nakryiko 	vma->vm_ops = &bpf_map_default_vmops;
913fc970227SAndrii Nakryiko 	vma->vm_private_data = map;
9141c71222eSSuren Baghdasaryan 	vm_flags_clear(vma, VM_MAYEXEC);
9151f6cb19bSAndrii Nakryiko 	if (!(vma->vm_flags & VM_WRITE))
9161f6cb19bSAndrii Nakryiko 		/* disallow re-mapping with PROT_WRITE */
9171c71222eSSuren Baghdasaryan 		vm_flags_clear(vma, VM_MAYWRITE);
918fc970227SAndrii Nakryiko 
919fc970227SAndrii Nakryiko 	err = map->ops->map_mmap(map, vma);
920fc970227SAndrii Nakryiko 	if (err)
921fc970227SAndrii Nakryiko 		goto out;
922fc970227SAndrii Nakryiko 
9231f6cb19bSAndrii Nakryiko 	if (vma->vm_flags & VM_MAYWRITE)
924353050beSDaniel Borkmann 		bpf_map_write_active_inc(map);
925fc970227SAndrii Nakryiko out:
926fc970227SAndrii Nakryiko 	mutex_unlock(&map->freeze_mutex);
927fc970227SAndrii Nakryiko 	return err;
928fc970227SAndrii Nakryiko }
929fc970227SAndrii Nakryiko 
930457f4436SAndrii Nakryiko static __poll_t bpf_map_poll(struct file *filp, struct poll_table_struct *pts)
931457f4436SAndrii Nakryiko {
932457f4436SAndrii Nakryiko 	struct bpf_map *map = filp->private_data;
933457f4436SAndrii Nakryiko 
934457f4436SAndrii Nakryiko 	if (map->ops->map_poll)
935457f4436SAndrii Nakryiko 		return map->ops->map_poll(map, filp, pts);
936457f4436SAndrii Nakryiko 
937457f4436SAndrii Nakryiko 	return EPOLLERR;
938457f4436SAndrii Nakryiko }
939457f4436SAndrii Nakryiko 
940f66e448cSChenbo Feng const struct file_operations bpf_map_fops = {
941f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
942f99bf205SDaniel Borkmann 	.show_fdinfo	= bpf_map_show_fdinfo,
943f99bf205SDaniel Borkmann #endif
94499c55f7dSAlexei Starovoitov 	.release	= bpf_map_release,
9456e71b04aSChenbo Feng 	.read		= bpf_dummy_read,
9466e71b04aSChenbo Feng 	.write		= bpf_dummy_write,
947fc970227SAndrii Nakryiko 	.mmap		= bpf_map_mmap,
948457f4436SAndrii Nakryiko 	.poll		= bpf_map_poll,
94999c55f7dSAlexei Starovoitov };
95099c55f7dSAlexei Starovoitov 
9516e71b04aSChenbo Feng int bpf_map_new_fd(struct bpf_map *map, int flags)
952aa79781bSDaniel Borkmann {
953afdb09c7SChenbo Feng 	int ret;
954afdb09c7SChenbo Feng 
955afdb09c7SChenbo Feng 	ret = security_bpf_map(map, OPEN_FMODE(flags));
956afdb09c7SChenbo Feng 	if (ret < 0)
957afdb09c7SChenbo Feng 		return ret;
958afdb09c7SChenbo Feng 
959aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-map", &bpf_map_fops, map,
9606e71b04aSChenbo Feng 				flags | O_CLOEXEC);
9616e71b04aSChenbo Feng }
9626e71b04aSChenbo Feng 
9636e71b04aSChenbo Feng int bpf_get_file_flag(int flags)
9646e71b04aSChenbo Feng {
9656e71b04aSChenbo Feng 	if ((flags & BPF_F_RDONLY) && (flags & BPF_F_WRONLY))
9666e71b04aSChenbo Feng 		return -EINVAL;
9676e71b04aSChenbo Feng 	if (flags & BPF_F_RDONLY)
9686e71b04aSChenbo Feng 		return O_RDONLY;
9696e71b04aSChenbo Feng 	if (flags & BPF_F_WRONLY)
9706e71b04aSChenbo Feng 		return O_WRONLY;
9716e71b04aSChenbo Feng 	return O_RDWR;
972aa79781bSDaniel Borkmann }
973aa79781bSDaniel Borkmann 
97499c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */
97599c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \
97699c55f7dSAlexei Starovoitov 	memchr_inv((void *) &attr->CMD##_LAST_FIELD + \
97799c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD), 0, \
97899c55f7dSAlexei Starovoitov 		   sizeof(*attr) - \
97999c55f7dSAlexei Starovoitov 		   offsetof(union bpf_attr, CMD##_LAST_FIELD) - \
98099c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD)) != NULL
98199c55f7dSAlexei Starovoitov 
9828e7ae251SMartin KaFai Lau /* dst and src must have at least "size" number of bytes.
9838e7ae251SMartin KaFai Lau  * Return strlen on success and < 0 on error.
984cb4d2b3fSMartin KaFai Lau  */
9858e7ae251SMartin KaFai Lau int bpf_obj_name_cpy(char *dst, const char *src, unsigned int size)
986cb4d2b3fSMartin KaFai Lau {
9878e7ae251SMartin KaFai Lau 	const char *end = src + size;
9888e7ae251SMartin KaFai Lau 	const char *orig_src = src;
989cb4d2b3fSMartin KaFai Lau 
9908e7ae251SMartin KaFai Lau 	memset(dst, 0, size);
9913e0ddc4fSDaniel Borkmann 	/* Copy all isalnum(), '_' and '.' chars. */
992cb4d2b3fSMartin KaFai Lau 	while (src < end && *src) {
9933e0ddc4fSDaniel Borkmann 		if (!isalnum(*src) &&
9943e0ddc4fSDaniel Borkmann 		    *src != '_' && *src != '.')
995cb4d2b3fSMartin KaFai Lau 			return -EINVAL;
996cb4d2b3fSMartin KaFai Lau 		*dst++ = *src++;
997cb4d2b3fSMartin KaFai Lau 	}
998cb4d2b3fSMartin KaFai Lau 
9998e7ae251SMartin KaFai Lau 	/* No '\0' found in "size" number of bytes */
1000cb4d2b3fSMartin KaFai Lau 	if (src == end)
1001cb4d2b3fSMartin KaFai Lau 		return -EINVAL;
1002cb4d2b3fSMartin KaFai Lau 
10038e7ae251SMartin KaFai Lau 	return src - orig_src;
1004cb4d2b3fSMartin KaFai Lau }
1005cb4d2b3fSMartin KaFai Lau 
1006e8d2bec0SDaniel Borkmann int map_check_no_btf(const struct bpf_map *map,
10071b2b234bSRoman Gushchin 		     const struct btf *btf,
1008e8d2bec0SDaniel Borkmann 		     const struct btf_type *key_type,
1009e8d2bec0SDaniel Borkmann 		     const struct btf_type *value_type)
1010e8d2bec0SDaniel Borkmann {
1011e8d2bec0SDaniel Borkmann 	return -ENOTSUPP;
1012e8d2bec0SDaniel Borkmann }
1013e8d2bec0SDaniel Borkmann 
1014a177fc2bSAndrii Nakryiko static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
1015a177fc2bSAndrii Nakryiko 			 const struct btf *btf, u32 btf_key_id, u32 btf_value_id)
1016e8d2bec0SDaniel Borkmann {
1017e8d2bec0SDaniel Borkmann 	const struct btf_type *key_type, *value_type;
1018e8d2bec0SDaniel Borkmann 	u32 key_size, value_size;
1019e8d2bec0SDaniel Borkmann 	int ret = 0;
1020e8d2bec0SDaniel Borkmann 
10212824ecb7SDaniel Borkmann 	/* Some maps allow key to be unspecified. */
10222824ecb7SDaniel Borkmann 	if (btf_key_id) {
1023e8d2bec0SDaniel Borkmann 		key_type = btf_type_id_size(btf, &btf_key_id, &key_size);
1024e8d2bec0SDaniel Borkmann 		if (!key_type || key_size != map->key_size)
1025e8d2bec0SDaniel Borkmann 			return -EINVAL;
10262824ecb7SDaniel Borkmann 	} else {
10272824ecb7SDaniel Borkmann 		key_type = btf_type_by_id(btf, 0);
10282824ecb7SDaniel Borkmann 		if (!map->ops->map_check_btf)
10292824ecb7SDaniel Borkmann 			return -EINVAL;
10302824ecb7SDaniel Borkmann 	}
1031e8d2bec0SDaniel Borkmann 
1032e8d2bec0SDaniel Borkmann 	value_type = btf_type_id_size(btf, &btf_value_id, &value_size);
1033e8d2bec0SDaniel Borkmann 	if (!value_type || value_size != map->value_size)
1034e8d2bec0SDaniel Borkmann 		return -EINVAL;
1035e8d2bec0SDaniel Borkmann 
1036f0c5941fSKumar Kartikeya Dwivedi 	map->record = btf_parse_fields(btf, value_type,
10379c395c1bSDave Marchevsky 				       BPF_SPIN_LOCK | BPF_TIMER | BPF_KPTR | BPF_LIST_HEAD |
1038d54730b5SDave Marchevsky 				       BPF_RB_ROOT | BPF_REFCOUNT,
1039db559117SKumar Kartikeya Dwivedi 				       map->value_size);
1040aa3496acSKumar Kartikeya Dwivedi 	if (!IS_ERR_OR_NULL(map->record)) {
1041aa3496acSKumar Kartikeya Dwivedi 		int i;
1042aa3496acSKumar Kartikeya Dwivedi 
1043a177fc2bSAndrii Nakryiko 		if (!bpf_token_capable(token, CAP_BPF)) {
104461df10c7SKumar Kartikeya Dwivedi 			ret = -EPERM;
104561df10c7SKumar Kartikeya Dwivedi 			goto free_map_tab;
104661df10c7SKumar Kartikeya Dwivedi 		}
104761df10c7SKumar Kartikeya Dwivedi 		if (map->map_flags & (BPF_F_RDONLY_PROG | BPF_F_WRONLY_PROG)) {
104861df10c7SKumar Kartikeya Dwivedi 			ret = -EACCES;
104961df10c7SKumar Kartikeya Dwivedi 			goto free_map_tab;
105061df10c7SKumar Kartikeya Dwivedi 		}
1051aa3496acSKumar Kartikeya Dwivedi 		for (i = 0; i < sizeof(map->record->field_mask) * 8; i++) {
1052aa3496acSKumar Kartikeya Dwivedi 			switch (map->record->field_mask & (1 << i)) {
1053aa3496acSKumar Kartikeya Dwivedi 			case 0:
1054aa3496acSKumar Kartikeya Dwivedi 				continue;
1055db559117SKumar Kartikeya Dwivedi 			case BPF_SPIN_LOCK:
1056db559117SKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
1057db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY &&
1058db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_CGROUP_STORAGE &&
1059db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_SK_STORAGE &&
1060db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_INODE_STORAGE &&
1061db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_TASK_STORAGE &&
1062db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_CGRP_STORAGE) {
1063db559117SKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
1064db559117SKumar Kartikeya Dwivedi 					goto free_map_tab;
1065db559117SKumar Kartikeya Dwivedi 				}
1066db559117SKumar Kartikeya Dwivedi 				break;
1067db559117SKumar Kartikeya Dwivedi 			case BPF_TIMER:
1068db559117SKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
1069db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
1070db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY) {
1071c237bfa5SKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
1072db559117SKumar Kartikeya Dwivedi 					goto free_map_tab;
1073db559117SKumar Kartikeya Dwivedi 				}
1074db559117SKumar Kartikeya Dwivedi 				break;
1075aa3496acSKumar Kartikeya Dwivedi 			case BPF_KPTR_UNREF:
1076aa3496acSKumar Kartikeya Dwivedi 			case BPF_KPTR_REF:
107755db92f4SYonghong Song 			case BPF_KPTR_PERCPU:
1078d54730b5SDave Marchevsky 			case BPF_REFCOUNT:
107961df10c7SKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
108065334e64SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_PERCPU_HASH &&
108161df10c7SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
108265334e64SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_PERCPU_HASH &&
10836df4ea1fSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY &&
10849db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_PERCPU_ARRAY &&
10859db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_SK_STORAGE &&
10869db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_INODE_STORAGE &&
10879db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_TASK_STORAGE &&
10889db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_CGRP_STORAGE) {
108961df10c7SKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
109061df10c7SKumar Kartikeya Dwivedi 					goto free_map_tab;
109161df10c7SKumar Kartikeya Dwivedi 				}
1092aa3496acSKumar Kartikeya Dwivedi 				break;
1093f0c5941fSKumar Kartikeya Dwivedi 			case BPF_LIST_HEAD:
10949c395c1bSDave Marchevsky 			case BPF_RB_ROOT:
1095f0c5941fSKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
1096f0c5941fSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
1097f0c5941fSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY) {
1098f0c5941fSKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
1099f0c5941fSKumar Kartikeya Dwivedi 					goto free_map_tab;
1100f0c5941fSKumar Kartikeya Dwivedi 				}
1101f0c5941fSKumar Kartikeya Dwivedi 				break;
1102aa3496acSKumar Kartikeya Dwivedi 			default:
1103aa3496acSKumar Kartikeya Dwivedi 				/* Fail if map_type checks are missing for a field type */
1104aa3496acSKumar Kartikeya Dwivedi 				ret = -EOPNOTSUPP;
1105aa3496acSKumar Kartikeya Dwivedi 				goto free_map_tab;
1106aa3496acSKumar Kartikeya Dwivedi 			}
1107aa3496acSKumar Kartikeya Dwivedi 		}
110861df10c7SKumar Kartikeya Dwivedi 	}
1109e8d2bec0SDaniel Borkmann 
1110865ce09aSKumar Kartikeya Dwivedi 	ret = btf_check_and_fixup_fields(btf, map->record);
1111865ce09aSKumar Kartikeya Dwivedi 	if (ret < 0)
1112865ce09aSKumar Kartikeya Dwivedi 		goto free_map_tab;
1113865ce09aSKumar Kartikeya Dwivedi 
111461df10c7SKumar Kartikeya Dwivedi 	if (map->ops->map_check_btf) {
111561df10c7SKumar Kartikeya Dwivedi 		ret = map->ops->map_check_btf(map, btf, key_type, value_type);
111661df10c7SKumar Kartikeya Dwivedi 		if (ret < 0)
111761df10c7SKumar Kartikeya Dwivedi 			goto free_map_tab;
111861df10c7SKumar Kartikeya Dwivedi 	}
111961df10c7SKumar Kartikeya Dwivedi 
112061df10c7SKumar Kartikeya Dwivedi 	return ret;
112161df10c7SKumar Kartikeya Dwivedi free_map_tab:
1122aa3496acSKumar Kartikeya Dwivedi 	bpf_map_free_record(map);
1123e8d2bec0SDaniel Borkmann 	return ret;
1124e8d2bec0SDaniel Borkmann }
1125e8d2bec0SDaniel Borkmann 
1126ed1ad5a7SAndrii Nakryiko static bool bpf_net_capable(void)
1127ed1ad5a7SAndrii Nakryiko {
1128ed1ad5a7SAndrii Nakryiko 	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
1129ed1ad5a7SAndrii Nakryiko }
1130ed1ad5a7SAndrii Nakryiko 
1131a177fc2bSAndrii Nakryiko #define BPF_MAP_CREATE_LAST_FIELD map_token_fd
113299c55f7dSAlexei Starovoitov /* called via syscall */
113399c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr)
113499c55f7dSAlexei Starovoitov {
113522db4122SAndrii Nakryiko 	const struct bpf_map_ops *ops;
1136a177fc2bSAndrii Nakryiko 	struct bpf_token *token = NULL;
113796eabe7aSMartin KaFai Lau 	int numa_node = bpf_map_attr_numa_node(attr);
113822db4122SAndrii Nakryiko 	u32 map_type = attr->map_type;
113999c55f7dSAlexei Starovoitov 	struct bpf_map *map;
1140a177fc2bSAndrii Nakryiko 	bool token_flag;
11416e71b04aSChenbo Feng 	int f_flags;
114299c55f7dSAlexei Starovoitov 	int err;
114399c55f7dSAlexei Starovoitov 
114499c55f7dSAlexei Starovoitov 	err = CHECK_ATTR(BPF_MAP_CREATE);
114599c55f7dSAlexei Starovoitov 	if (err)
114699c55f7dSAlexei Starovoitov 		return -EINVAL;
114799c55f7dSAlexei Starovoitov 
1148a177fc2bSAndrii Nakryiko 	/* check BPF_F_TOKEN_FD flag, remember if it's set, and then clear it
1149a177fc2bSAndrii Nakryiko 	 * to avoid per-map type checks tripping on unknown flag
1150a177fc2bSAndrii Nakryiko 	 */
1151a177fc2bSAndrii Nakryiko 	token_flag = attr->map_flags & BPF_F_TOKEN_FD;
1152a177fc2bSAndrii Nakryiko 	attr->map_flags &= ~BPF_F_TOKEN_FD;
1153a177fc2bSAndrii Nakryiko 
115485d33df3SMartin KaFai Lau 	if (attr->btf_vmlinux_value_type_id) {
115585d33df3SMartin KaFai Lau 		if (attr->map_type != BPF_MAP_TYPE_STRUCT_OPS ||
115685d33df3SMartin KaFai Lau 		    attr->btf_key_type_id || attr->btf_value_type_id)
115785d33df3SMartin KaFai Lau 			return -EINVAL;
115885d33df3SMartin KaFai Lau 	} else if (attr->btf_key_type_id && !attr->btf_value_type_id) {
115985d33df3SMartin KaFai Lau 		return -EINVAL;
116085d33df3SMartin KaFai Lau 	}
116185d33df3SMartin KaFai Lau 
11629330986cSJoanne Koong 	if (attr->map_type != BPF_MAP_TYPE_BLOOM_FILTER &&
11639330986cSJoanne Koong 	    attr->map_extra != 0)
11649330986cSJoanne Koong 		return -EINVAL;
11659330986cSJoanne Koong 
11666e71b04aSChenbo Feng 	f_flags = bpf_get_file_flag(attr->map_flags);
11676e71b04aSChenbo Feng 	if (f_flags < 0)
11686e71b04aSChenbo Feng 		return f_flags;
11696e71b04aSChenbo Feng 
117096eabe7aSMartin KaFai Lau 	if (numa_node != NUMA_NO_NODE &&
117196e5ae4eSEric Dumazet 	    ((unsigned int)numa_node >= nr_node_ids ||
117296e5ae4eSEric Dumazet 	     !node_online(numa_node)))
117396eabe7aSMartin KaFai Lau 		return -EINVAL;
117496eabe7aSMartin KaFai Lau 
117599c55f7dSAlexei Starovoitov 	/* find map type and init map: hashtable vs rbtree vs bloom vs ... */
117622db4122SAndrii Nakryiko 	map_type = attr->map_type;
117722db4122SAndrii Nakryiko 	if (map_type >= ARRAY_SIZE(bpf_map_types))
117822db4122SAndrii Nakryiko 		return -EINVAL;
117922db4122SAndrii Nakryiko 	map_type = array_index_nospec(map_type, ARRAY_SIZE(bpf_map_types));
118022db4122SAndrii Nakryiko 	ops = bpf_map_types[map_type];
118122db4122SAndrii Nakryiko 	if (!ops)
118222db4122SAndrii Nakryiko 		return -EINVAL;
118322db4122SAndrii Nakryiko 
118422db4122SAndrii Nakryiko 	if (ops->map_alloc_check) {
118522db4122SAndrii Nakryiko 		err = ops->map_alloc_check(attr);
118622db4122SAndrii Nakryiko 		if (err)
118722db4122SAndrii Nakryiko 			return err;
118822db4122SAndrii Nakryiko 	}
118922db4122SAndrii Nakryiko 	if (attr->map_ifindex)
119022db4122SAndrii Nakryiko 		ops = &bpf_map_offload_ops;
119122db4122SAndrii Nakryiko 	if (!ops->map_mem_usage)
119222db4122SAndrii Nakryiko 		return -EINVAL;
119322db4122SAndrii Nakryiko 
1194a177fc2bSAndrii Nakryiko 	if (token_flag) {
1195a177fc2bSAndrii Nakryiko 		token = bpf_token_get_from_fd(attr->map_token_fd);
1196a177fc2bSAndrii Nakryiko 		if (IS_ERR(token))
1197a177fc2bSAndrii Nakryiko 			return PTR_ERR(token);
1198a177fc2bSAndrii Nakryiko 
1199a177fc2bSAndrii Nakryiko 		/* if current token doesn't grant map creation permissions,
1200a177fc2bSAndrii Nakryiko 		 * then we can't use this token, so ignore it and rely on
1201a177fc2bSAndrii Nakryiko 		 * system-wide capabilities checks
1202a177fc2bSAndrii Nakryiko 		 */
1203a177fc2bSAndrii Nakryiko 		if (!bpf_token_allow_cmd(token, BPF_MAP_CREATE) ||
1204a177fc2bSAndrii Nakryiko 		    !bpf_token_allow_map_type(token, attr->map_type)) {
1205a177fc2bSAndrii Nakryiko 			bpf_token_put(token);
1206a177fc2bSAndrii Nakryiko 			token = NULL;
1207a177fc2bSAndrii Nakryiko 		}
1208a177fc2bSAndrii Nakryiko 	}
1209a177fc2bSAndrii Nakryiko 
1210a177fc2bSAndrii Nakryiko 	err = -EPERM;
1211a177fc2bSAndrii Nakryiko 
12121d28635aSAndrii Nakryiko 	/* Intent here is for unprivileged_bpf_disabled to block BPF map
12131d28635aSAndrii Nakryiko 	 * creation for unprivileged users; other actions depend
12141d28635aSAndrii Nakryiko 	 * on fd availability and access to bpffs, so are dependent on
12151d28635aSAndrii Nakryiko 	 * object creation success. Even with unprivileged BPF disabled,
12161d28635aSAndrii Nakryiko 	 * capability checks are still carried out.
12171d28635aSAndrii Nakryiko 	 */
1218a177fc2bSAndrii Nakryiko 	if (sysctl_unprivileged_bpf_disabled && !bpf_token_capable(token, CAP_BPF))
1219a177fc2bSAndrii Nakryiko 		goto put_token;
12201d28635aSAndrii Nakryiko 
12216c3eba1cSAndrii Nakryiko 	/* check privileged map type permissions */
12226c3eba1cSAndrii Nakryiko 	switch (map_type) {
12236c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_ARRAY:
12246c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PERCPU_ARRAY:
12256c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PROG_ARRAY:
12266c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
12276c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_CGROUP_ARRAY:
12286c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_ARRAY_OF_MAPS:
12296c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_HASH:
12306c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PERCPU_HASH:
12316c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_HASH_OF_MAPS:
12326c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_RINGBUF:
12336c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_USER_RINGBUF:
12346c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_CGROUP_STORAGE:
12356c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE:
12366c3eba1cSAndrii Nakryiko 		/* unprivileged */
12376c3eba1cSAndrii Nakryiko 		break;
12386c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_SK_STORAGE:
12396c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_INODE_STORAGE:
12406c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_TASK_STORAGE:
12416c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_CGRP_STORAGE:
12426c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_BLOOM_FILTER:
12436c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_LPM_TRIE:
12446c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY:
12456c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_STACK_TRACE:
12466c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_QUEUE:
12476c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_STACK:
12486c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_LRU_HASH:
12496c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_LRU_PERCPU_HASH:
12506c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_STRUCT_OPS:
12516c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_CPUMAP:
1252a177fc2bSAndrii Nakryiko 		if (!bpf_token_capable(token, CAP_BPF))
1253a177fc2bSAndrii Nakryiko 			goto put_token;
12546c3eba1cSAndrii Nakryiko 		break;
12556c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_SOCKMAP:
12566c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_SOCKHASH:
12576c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_DEVMAP:
12586c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_DEVMAP_HASH:
12596c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_XSKMAP:
1260a177fc2bSAndrii Nakryiko 		if (!bpf_token_capable(token, CAP_NET_ADMIN))
1261a177fc2bSAndrii Nakryiko 			goto put_token;
12626c3eba1cSAndrii Nakryiko 		break;
12636c3eba1cSAndrii Nakryiko 	default:
12646c3eba1cSAndrii Nakryiko 		WARN(1, "unsupported map type %d", map_type);
1265a177fc2bSAndrii Nakryiko 		goto put_token;
12666c3eba1cSAndrii Nakryiko 	}
12676c3eba1cSAndrii Nakryiko 
126822db4122SAndrii Nakryiko 	map = ops->map_alloc(attr);
1269a177fc2bSAndrii Nakryiko 	if (IS_ERR(map)) {
1270a177fc2bSAndrii Nakryiko 		err = PTR_ERR(map);
1271a177fc2bSAndrii Nakryiko 		goto put_token;
1272a177fc2bSAndrii Nakryiko 	}
127322db4122SAndrii Nakryiko 	map->ops = ops;
127422db4122SAndrii Nakryiko 	map->map_type = map_type;
127599c55f7dSAlexei Starovoitov 
12768e7ae251SMartin KaFai Lau 	err = bpf_obj_name_cpy(map->name, attr->map_name,
12778e7ae251SMartin KaFai Lau 			       sizeof(attr->map_name));
12788e7ae251SMartin KaFai Lau 	if (err < 0)
1279b936ca64SRoman Gushchin 		goto free_map;
1280ad5b177bSMartin KaFai Lau 
12811e0bd5a0SAndrii Nakryiko 	atomic64_set(&map->refcnt, 1);
12821e0bd5a0SAndrii Nakryiko 	atomic64_set(&map->usercnt, 1);
1283fc970227SAndrii Nakryiko 	mutex_init(&map->freeze_mutex);
1284f45d5b6cSToke Hoiland-Jorgensen 	spin_lock_init(&map->owner.lock);
128599c55f7dSAlexei Starovoitov 
128685d33df3SMartin KaFai Lau 	if (attr->btf_key_type_id || attr->btf_value_type_id ||
128785d33df3SMartin KaFai Lau 	    /* Even the map's value is a kernel's struct,
128885d33df3SMartin KaFai Lau 	     * the bpf_prog.o must have BTF to begin with
128985d33df3SMartin KaFai Lau 	     * to figure out the corresponding kernel's
129085d33df3SMartin KaFai Lau 	     * counter part.  Thus, attr->btf_fd has
129185d33df3SMartin KaFai Lau 	     * to be valid also.
129285d33df3SMartin KaFai Lau 	     */
129385d33df3SMartin KaFai Lau 	    attr->btf_vmlinux_value_type_id) {
1294a26ca7c9SMartin KaFai Lau 		struct btf *btf;
1295a26ca7c9SMartin KaFai Lau 
1296a26ca7c9SMartin KaFai Lau 		btf = btf_get_by_fd(attr->btf_fd);
1297a26ca7c9SMartin KaFai Lau 		if (IS_ERR(btf)) {
1298a26ca7c9SMartin KaFai Lau 			err = PTR_ERR(btf);
1299b936ca64SRoman Gushchin 			goto free_map;
1300a26ca7c9SMartin KaFai Lau 		}
1301350a5c4dSAlexei Starovoitov 		if (btf_is_kernel(btf)) {
1302350a5c4dSAlexei Starovoitov 			btf_put(btf);
1303350a5c4dSAlexei Starovoitov 			err = -EACCES;
1304350a5c4dSAlexei Starovoitov 			goto free_map;
1305350a5c4dSAlexei Starovoitov 		}
130685d33df3SMartin KaFai Lau 		map->btf = btf;
1307a26ca7c9SMartin KaFai Lau 
130885d33df3SMartin KaFai Lau 		if (attr->btf_value_type_id) {
1309a177fc2bSAndrii Nakryiko 			err = map_check_btf(map, token, btf, attr->btf_key_type_id,
13109b2cf328SMartin KaFai Lau 					    attr->btf_value_type_id);
131185d33df3SMartin KaFai Lau 			if (err)
1312b936ca64SRoman Gushchin 				goto free_map;
1313a26ca7c9SMartin KaFai Lau 		}
1314a26ca7c9SMartin KaFai Lau 
13159b2cf328SMartin KaFai Lau 		map->btf_key_type_id = attr->btf_key_type_id;
13169b2cf328SMartin KaFai Lau 		map->btf_value_type_id = attr->btf_value_type_id;
131785d33df3SMartin KaFai Lau 		map->btf_vmlinux_value_type_id =
131885d33df3SMartin KaFai Lau 			attr->btf_vmlinux_value_type_id;
1319a26ca7c9SMartin KaFai Lau 	}
1320a26ca7c9SMartin KaFai Lau 
1321d17aff80SAndrii Nakryiko 	err = security_bpf_map_alloc(map);
13224d7d7f69SKumar Kartikeya Dwivedi 	if (err)
1323d17aff80SAndrii Nakryiko 		goto free_map;
13244d7d7f69SKumar Kartikeya Dwivedi 
1325f3f1c054SMartin KaFai Lau 	err = bpf_map_alloc_id(map);
1326f3f1c054SMartin KaFai Lau 	if (err)
1327b936ca64SRoman Gushchin 		goto free_map_sec;
1328f3f1c054SMartin KaFai Lau 
132948edc1f7SRoman Gushchin 	bpf_map_save_memcg(map);
1330a177fc2bSAndrii Nakryiko 	bpf_token_put(token);
133148edc1f7SRoman Gushchin 
13326e71b04aSChenbo Feng 	err = bpf_map_new_fd(map, f_flags);
1333bd5f5f4eSMartin KaFai Lau 	if (err < 0) {
1334bd5f5f4eSMartin KaFai Lau 		/* failed to allocate fd.
1335352d20d6SPeng Sun 		 * bpf_map_put_with_uref() is needed because the above
1336bd5f5f4eSMartin KaFai Lau 		 * bpf_map_alloc_id() has published the map
1337bd5f5f4eSMartin KaFai Lau 		 * to the userspace and the userspace may
1338bd5f5f4eSMartin KaFai Lau 		 * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID.
1339bd5f5f4eSMartin KaFai Lau 		 */
1340352d20d6SPeng Sun 		bpf_map_put_with_uref(map);
1341bd5f5f4eSMartin KaFai Lau 		return err;
1342bd5f5f4eSMartin KaFai Lau 	}
134399c55f7dSAlexei Starovoitov 
134499c55f7dSAlexei Starovoitov 	return err;
134599c55f7dSAlexei Starovoitov 
1346afdb09c7SChenbo Feng free_map_sec:
1347afdb09c7SChenbo Feng 	security_bpf_map_free(map);
1348b936ca64SRoman Gushchin free_map:
1349a26ca7c9SMartin KaFai Lau 	btf_put(map->btf);
135099c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
1351a177fc2bSAndrii Nakryiko put_token:
1352a177fc2bSAndrii Nakryiko 	bpf_token_put(token);
135399c55f7dSAlexei Starovoitov 	return err;
135499c55f7dSAlexei Starovoitov }
135599c55f7dSAlexei Starovoitov 
1356db20fd2bSAlexei Starovoitov /* if error is returned, fd is released.
1357db20fd2bSAlexei Starovoitov  * On success caller should complete fd access with matching fdput()
1358db20fd2bSAlexei Starovoitov  */
1359c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f)
1360db20fd2bSAlexei Starovoitov {
1361db20fd2bSAlexei Starovoitov 	if (!f.file)
1362db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EBADF);
1363db20fd2bSAlexei Starovoitov 	if (f.file->f_op != &bpf_map_fops) {
1364db20fd2bSAlexei Starovoitov 		fdput(f);
1365db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EINVAL);
1366db20fd2bSAlexei Starovoitov 	}
1367db20fd2bSAlexei Starovoitov 
1368c2101297SDaniel Borkmann 	return f.file->private_data;
1369c2101297SDaniel Borkmann }
1370c2101297SDaniel Borkmann 
13711e0bd5a0SAndrii Nakryiko void bpf_map_inc(struct bpf_map *map)
1372c9da161cSDaniel Borkmann {
13731e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->refcnt);
1374c9da161cSDaniel Borkmann }
1375630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_inc);
1376c9da161cSDaniel Borkmann 
13771e0bd5a0SAndrii Nakryiko void bpf_map_inc_with_uref(struct bpf_map *map)
13781e0bd5a0SAndrii Nakryiko {
13791e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->refcnt);
13801e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->usercnt);
13811e0bd5a0SAndrii Nakryiko }
13821e0bd5a0SAndrii Nakryiko EXPORT_SYMBOL_GPL(bpf_map_inc_with_uref);
13831e0bd5a0SAndrii Nakryiko 
13841ed4d924SMartin KaFai Lau struct bpf_map *bpf_map_get(u32 ufd)
13851ed4d924SMartin KaFai Lau {
13861ed4d924SMartin KaFai Lau 	struct fd f = fdget(ufd);
13871ed4d924SMartin KaFai Lau 	struct bpf_map *map;
13881ed4d924SMartin KaFai Lau 
13891ed4d924SMartin KaFai Lau 	map = __bpf_map_get(f);
13901ed4d924SMartin KaFai Lau 	if (IS_ERR(map))
13911ed4d924SMartin KaFai Lau 		return map;
13921ed4d924SMartin KaFai Lau 
13931ed4d924SMartin KaFai Lau 	bpf_map_inc(map);
13941ed4d924SMartin KaFai Lau 	fdput(f);
13951ed4d924SMartin KaFai Lau 
13961ed4d924SMartin KaFai Lau 	return map;
13971ed4d924SMartin KaFai Lau }
1398b1d18a75SAlexei Starovoitov EXPORT_SYMBOL(bpf_map_get);
13991ed4d924SMartin KaFai Lau 
1400c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd)
1401c2101297SDaniel Borkmann {
1402c2101297SDaniel Borkmann 	struct fd f = fdget(ufd);
1403c2101297SDaniel Borkmann 	struct bpf_map *map;
1404c2101297SDaniel Borkmann 
1405c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1406c2101297SDaniel Borkmann 	if (IS_ERR(map))
1407c2101297SDaniel Borkmann 		return map;
1408c2101297SDaniel Borkmann 
14091e0bd5a0SAndrii Nakryiko 	bpf_map_inc_with_uref(map);
1410c2101297SDaniel Borkmann 	fdput(f);
1411db20fd2bSAlexei Starovoitov 
1412db20fd2bSAlexei Starovoitov 	return map;
1413db20fd2bSAlexei Starovoitov }
1414db20fd2bSAlexei Starovoitov 
1415b671c206SKui-Feng Lee /* map_idr_lock should have been held or the map should have been
1416b671c206SKui-Feng Lee  * protected by rcu read lock.
1417b671c206SKui-Feng Lee  */
1418b671c206SKui-Feng Lee struct bpf_map *__bpf_map_inc_not_zero(struct bpf_map *map, bool uref)
1419bd5f5f4eSMartin KaFai Lau {
1420bd5f5f4eSMartin KaFai Lau 	int refold;
1421bd5f5f4eSMartin KaFai Lau 
14221e0bd5a0SAndrii Nakryiko 	refold = atomic64_fetch_add_unless(&map->refcnt, 1, 0);
1423bd5f5f4eSMartin KaFai Lau 	if (!refold)
1424bd5f5f4eSMartin KaFai Lau 		return ERR_PTR(-ENOENT);
1425bd5f5f4eSMartin KaFai Lau 	if (uref)
14261e0bd5a0SAndrii Nakryiko 		atomic64_inc(&map->usercnt);
1427bd5f5f4eSMartin KaFai Lau 
1428bd5f5f4eSMartin KaFai Lau 	return map;
1429bd5f5f4eSMartin KaFai Lau }
1430bd5f5f4eSMartin KaFai Lau 
14311e0bd5a0SAndrii Nakryiko struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map)
1432b0e4701cSStanislav Fomichev {
1433b0e4701cSStanislav Fomichev 	spin_lock_bh(&map_idr_lock);
14341e0bd5a0SAndrii Nakryiko 	map = __bpf_map_inc_not_zero(map, false);
1435b0e4701cSStanislav Fomichev 	spin_unlock_bh(&map_idr_lock);
1436b0e4701cSStanislav Fomichev 
1437b0e4701cSStanislav Fomichev 	return map;
1438b0e4701cSStanislav Fomichev }
1439b0e4701cSStanislav Fomichev EXPORT_SYMBOL_GPL(bpf_map_inc_not_zero);
1440b0e4701cSStanislav Fomichev 
1441b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
1442b8cdc051SAlexei Starovoitov {
1443b8cdc051SAlexei Starovoitov 	return -ENOTSUPP;
1444b8cdc051SAlexei Starovoitov }
1445b8cdc051SAlexei Starovoitov 
1446c9d29f46SMauricio Vasquez B static void *__bpf_copy_key(void __user *ukey, u64 key_size)
1447c9d29f46SMauricio Vasquez B {
1448c9d29f46SMauricio Vasquez B 	if (key_size)
144944779a4bSStanislav Fomichev 		return vmemdup_user(ukey, key_size);
1450c9d29f46SMauricio Vasquez B 
1451c9d29f46SMauricio Vasquez B 	if (ukey)
1452c9d29f46SMauricio Vasquez B 		return ERR_PTR(-EINVAL);
1453c9d29f46SMauricio Vasquez B 
1454c9d29f46SMauricio Vasquez B 	return NULL;
1455c9d29f46SMauricio Vasquez B }
1456c9d29f46SMauricio Vasquez B 
1457af2ac3e1SAlexei Starovoitov static void *___bpf_copy_key(bpfptr_t ukey, u64 key_size)
1458af2ac3e1SAlexei Starovoitov {
1459af2ac3e1SAlexei Starovoitov 	if (key_size)
146044779a4bSStanislav Fomichev 		return kvmemdup_bpfptr(ukey, key_size);
1461af2ac3e1SAlexei Starovoitov 
1462af2ac3e1SAlexei Starovoitov 	if (!bpfptr_is_null(ukey))
1463af2ac3e1SAlexei Starovoitov 		return ERR_PTR(-EINVAL);
1464af2ac3e1SAlexei Starovoitov 
1465af2ac3e1SAlexei Starovoitov 	return NULL;
1466af2ac3e1SAlexei Starovoitov }
1467af2ac3e1SAlexei Starovoitov 
1468db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
146996049f3aSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD flags
1470db20fd2bSAlexei Starovoitov 
1471db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr)
1472db20fd2bSAlexei Starovoitov {
1473535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
1474535e7b4bSMickaël Salaün 	void __user *uvalue = u64_to_user_ptr(attr->value);
1475db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1476db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
147715c14a3dSBrian Vazquez 	void *key, *value;
147815a07b33SAlexei Starovoitov 	u32 value_size;
1479592867bfSDaniel Borkmann 	struct fd f;
1480db20fd2bSAlexei Starovoitov 	int err;
1481db20fd2bSAlexei Starovoitov 
1482db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
1483db20fd2bSAlexei Starovoitov 		return -EINVAL;
1484db20fd2bSAlexei Starovoitov 
148596049f3aSAlexei Starovoitov 	if (attr->flags & ~BPF_F_LOCK)
148696049f3aSAlexei Starovoitov 		return -EINVAL;
148796049f3aSAlexei Starovoitov 
1488592867bfSDaniel Borkmann 	f = fdget(ufd);
1489c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1490db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1491db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
149287df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
14936e71b04aSChenbo Feng 		err = -EPERM;
14946e71b04aSChenbo Feng 		goto err_put;
14956e71b04aSChenbo Feng 	}
14966e71b04aSChenbo Feng 
149796049f3aSAlexei Starovoitov 	if ((attr->flags & BPF_F_LOCK) &&
1498db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
149996049f3aSAlexei Starovoitov 		err = -EINVAL;
150096049f3aSAlexei Starovoitov 		goto err_put;
150196049f3aSAlexei Starovoitov 	}
150296049f3aSAlexei Starovoitov 
1503c9d29f46SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
1504e4448ed8SAl Viro 	if (IS_ERR(key)) {
1505e4448ed8SAl Viro 		err = PTR_ERR(key);
1506db20fd2bSAlexei Starovoitov 		goto err_put;
1507e4448ed8SAl Viro 	}
1508db20fd2bSAlexei Starovoitov 
150915c14a3dSBrian Vazquez 	value_size = bpf_map_value_size(map);
151015a07b33SAlexei Starovoitov 
15118ebe667cSAlexei Starovoitov 	err = -ENOMEM;
1512f0dce1d9SStanislav Fomichev 	value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN);
1513db20fd2bSAlexei Starovoitov 	if (!value)
15148ebe667cSAlexei Starovoitov 		goto free_key;
15158ebe667cSAlexei Starovoitov 
15169330986cSJoanne Koong 	if (map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) {
15179330986cSJoanne Koong 		if (copy_from_user(value, uvalue, value_size))
15189330986cSJoanne Koong 			err = -EFAULT;
15199330986cSJoanne Koong 		else
15209330986cSJoanne Koong 			err = bpf_map_copy_value(map, key, value, attr->flags);
15219330986cSJoanne Koong 		goto free_value;
15229330986cSJoanne Koong 	}
15239330986cSJoanne Koong 
152415c14a3dSBrian Vazquez 	err = bpf_map_copy_value(map, key, value, attr->flags);
152515a07b33SAlexei Starovoitov 	if (err)
15268ebe667cSAlexei Starovoitov 		goto free_value;
1527db20fd2bSAlexei Starovoitov 
1528db20fd2bSAlexei Starovoitov 	err = -EFAULT;
152915a07b33SAlexei Starovoitov 	if (copy_to_user(uvalue, value, value_size) != 0)
15308ebe667cSAlexei Starovoitov 		goto free_value;
1531db20fd2bSAlexei Starovoitov 
1532db20fd2bSAlexei Starovoitov 	err = 0;
1533db20fd2bSAlexei Starovoitov 
15348ebe667cSAlexei Starovoitov free_value:
1535f0dce1d9SStanislav Fomichev 	kvfree(value);
1536db20fd2bSAlexei Starovoitov free_key:
153744779a4bSStanislav Fomichev 	kvfree(key);
1538db20fd2bSAlexei Starovoitov err_put:
1539db20fd2bSAlexei Starovoitov 	fdput(f);
1540db20fd2bSAlexei Starovoitov 	return err;
1541db20fd2bSAlexei Starovoitov }
1542db20fd2bSAlexei Starovoitov 
15431ae80cf3SDaniel Colascione 
15443274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags
1545db20fd2bSAlexei Starovoitov 
1546af2ac3e1SAlexei Starovoitov static int map_update_elem(union bpf_attr *attr, bpfptr_t uattr)
1547db20fd2bSAlexei Starovoitov {
1548af2ac3e1SAlexei Starovoitov 	bpfptr_t ukey = make_bpfptr(attr->key, uattr.is_kernel);
1549af2ac3e1SAlexei Starovoitov 	bpfptr_t uvalue = make_bpfptr(attr->value, uattr.is_kernel);
1550db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1551db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1552db20fd2bSAlexei Starovoitov 	void *key, *value;
155315a07b33SAlexei Starovoitov 	u32 value_size;
1554592867bfSDaniel Borkmann 	struct fd f;
1555db20fd2bSAlexei Starovoitov 	int err;
1556db20fd2bSAlexei Starovoitov 
1557db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM))
1558db20fd2bSAlexei Starovoitov 		return -EINVAL;
1559db20fd2bSAlexei Starovoitov 
1560592867bfSDaniel Borkmann 	f = fdget(ufd);
1561c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1562db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1563db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
1564353050beSDaniel Borkmann 	bpf_map_write_active_inc(map);
156587df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
15666e71b04aSChenbo Feng 		err = -EPERM;
15676e71b04aSChenbo Feng 		goto err_put;
15686e71b04aSChenbo Feng 	}
15696e71b04aSChenbo Feng 
157096049f3aSAlexei Starovoitov 	if ((attr->flags & BPF_F_LOCK) &&
1571db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
157296049f3aSAlexei Starovoitov 		err = -EINVAL;
157396049f3aSAlexei Starovoitov 		goto err_put;
157496049f3aSAlexei Starovoitov 	}
157596049f3aSAlexei Starovoitov 
1576af2ac3e1SAlexei Starovoitov 	key = ___bpf_copy_key(ukey, map->key_size);
1577e4448ed8SAl Viro 	if (IS_ERR(key)) {
1578e4448ed8SAl Viro 		err = PTR_ERR(key);
1579db20fd2bSAlexei Starovoitov 		goto err_put;
1580e4448ed8SAl Viro 	}
1581db20fd2bSAlexei Starovoitov 
1582f0dce1d9SStanislav Fomichev 	value_size = bpf_map_value_size(map);
1583a02c118eSWang Yufen 	value = kvmemdup_bpfptr(uvalue, value_size);
1584a02c118eSWang Yufen 	if (IS_ERR(value)) {
1585a02c118eSWang Yufen 		err = PTR_ERR(value);
1586db20fd2bSAlexei Starovoitov 		goto free_key;
1587a02c118eSWang Yufen 	}
1588db20fd2bSAlexei Starovoitov 
15893af43ba4SHou Tao 	err = bpf_map_update_value(map, f.file, key, value, attr->flags);
159067ad2c73SHou Tao 	if (!err)
159137ba5b59SHou Tao 		maybe_wait_bpf_programs(map);
15926710e112SJesper Dangaard Brouer 
1593f0dce1d9SStanislav Fomichev 	kvfree(value);
1594db20fd2bSAlexei Starovoitov free_key:
159544779a4bSStanislav Fomichev 	kvfree(key);
1596db20fd2bSAlexei Starovoitov err_put:
1597353050beSDaniel Borkmann 	bpf_map_write_active_dec(map);
1598db20fd2bSAlexei Starovoitov 	fdput(f);
1599db20fd2bSAlexei Starovoitov 	return err;
1600db20fd2bSAlexei Starovoitov }
1601db20fd2bSAlexei Starovoitov 
1602db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key
1603db20fd2bSAlexei Starovoitov 
1604b88df697SBenjamin Tissoires static int map_delete_elem(union bpf_attr *attr, bpfptr_t uattr)
1605db20fd2bSAlexei Starovoitov {
1606b88df697SBenjamin Tissoires 	bpfptr_t ukey = make_bpfptr(attr->key, uattr.is_kernel);
1607db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1608db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1609592867bfSDaniel Borkmann 	struct fd f;
1610db20fd2bSAlexei Starovoitov 	void *key;
1611db20fd2bSAlexei Starovoitov 	int err;
1612db20fd2bSAlexei Starovoitov 
1613db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_DELETE_ELEM))
1614db20fd2bSAlexei Starovoitov 		return -EINVAL;
1615db20fd2bSAlexei Starovoitov 
1616592867bfSDaniel Borkmann 	f = fdget(ufd);
1617c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1618db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1619db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
1620353050beSDaniel Borkmann 	bpf_map_write_active_inc(map);
162187df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
16226e71b04aSChenbo Feng 		err = -EPERM;
16236e71b04aSChenbo Feng 		goto err_put;
16246e71b04aSChenbo Feng 	}
16256e71b04aSChenbo Feng 
1626b88df697SBenjamin Tissoires 	key = ___bpf_copy_key(ukey, map->key_size);
1627e4448ed8SAl Viro 	if (IS_ERR(key)) {
1628e4448ed8SAl Viro 		err = PTR_ERR(key);
1629db20fd2bSAlexei Starovoitov 		goto err_put;
1630e4448ed8SAl Viro 	}
1631db20fd2bSAlexei Starovoitov 
16329d03ebc7SStanislav Fomichev 	if (bpf_map_is_offloaded(map)) {
1633a3884572SJakub Kicinski 		err = bpf_map_offload_delete_elem(map, key);
1634a3884572SJakub Kicinski 		goto out;
163585d33df3SMartin KaFai Lau 	} else if (IS_FD_PROG_ARRAY(map) ||
163685d33df3SMartin KaFai Lau 		   map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
163785d33df3SMartin KaFai Lau 		/* These maps require sleepable context */
1638da765a2fSDaniel Borkmann 		err = map->ops->map_delete_elem(map, key);
1639da765a2fSDaniel Borkmann 		goto out;
1640a3884572SJakub Kicinski 	}
1641a3884572SJakub Kicinski 
1642b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
1643db20fd2bSAlexei Starovoitov 	rcu_read_lock();
1644db20fd2bSAlexei Starovoitov 	err = map->ops->map_delete_elem(map, key);
1645db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
1646b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
164767ad2c73SHou Tao 	if (!err)
16481ae80cf3SDaniel Colascione 		maybe_wait_bpf_programs(map);
1649a3884572SJakub Kicinski out:
165044779a4bSStanislav Fomichev 	kvfree(key);
1651db20fd2bSAlexei Starovoitov err_put:
1652353050beSDaniel Borkmann 	bpf_map_write_active_dec(map);
1653db20fd2bSAlexei Starovoitov 	fdput(f);
1654db20fd2bSAlexei Starovoitov 	return err;
1655db20fd2bSAlexei Starovoitov }
1656db20fd2bSAlexei Starovoitov 
1657db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
1658db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key
1659db20fd2bSAlexei Starovoitov 
1660db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr)
1661db20fd2bSAlexei Starovoitov {
1662535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
1663535e7b4bSMickaël Salaün 	void __user *unext_key = u64_to_user_ptr(attr->next_key);
1664db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1665db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1666db20fd2bSAlexei Starovoitov 	void *key, *next_key;
1667592867bfSDaniel Borkmann 	struct fd f;
1668db20fd2bSAlexei Starovoitov 	int err;
1669db20fd2bSAlexei Starovoitov 
1670db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY))
1671db20fd2bSAlexei Starovoitov 		return -EINVAL;
1672db20fd2bSAlexei Starovoitov 
1673592867bfSDaniel Borkmann 	f = fdget(ufd);
1674c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1675db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1676db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
167787df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
16786e71b04aSChenbo Feng 		err = -EPERM;
16796e71b04aSChenbo Feng 		goto err_put;
16806e71b04aSChenbo Feng 	}
16816e71b04aSChenbo Feng 
16828fe45924STeng Qin 	if (ukey) {
1683c9d29f46SMauricio Vasquez B 		key = __bpf_copy_key(ukey, map->key_size);
1684e4448ed8SAl Viro 		if (IS_ERR(key)) {
1685e4448ed8SAl Viro 			err = PTR_ERR(key);
1686db20fd2bSAlexei Starovoitov 			goto err_put;
1687e4448ed8SAl Viro 		}
16888fe45924STeng Qin 	} else {
16898fe45924STeng Qin 		key = NULL;
16908fe45924STeng Qin 	}
1691db20fd2bSAlexei Starovoitov 
1692db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
169344779a4bSStanislav Fomichev 	next_key = kvmalloc(map->key_size, GFP_USER);
1694db20fd2bSAlexei Starovoitov 	if (!next_key)
1695db20fd2bSAlexei Starovoitov 		goto free_key;
1696db20fd2bSAlexei Starovoitov 
16979d03ebc7SStanislav Fomichev 	if (bpf_map_is_offloaded(map)) {
1698a3884572SJakub Kicinski 		err = bpf_map_offload_get_next_key(map, key, next_key);
1699a3884572SJakub Kicinski 		goto out;
1700a3884572SJakub Kicinski 	}
1701a3884572SJakub Kicinski 
1702db20fd2bSAlexei Starovoitov 	rcu_read_lock();
1703db20fd2bSAlexei Starovoitov 	err = map->ops->map_get_next_key(map, key, next_key);
1704db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
1705a3884572SJakub Kicinski out:
1706db20fd2bSAlexei Starovoitov 	if (err)
1707db20fd2bSAlexei Starovoitov 		goto free_next_key;
1708db20fd2bSAlexei Starovoitov 
1709db20fd2bSAlexei Starovoitov 	err = -EFAULT;
1710db20fd2bSAlexei Starovoitov 	if (copy_to_user(unext_key, next_key, map->key_size) != 0)
1711db20fd2bSAlexei Starovoitov 		goto free_next_key;
1712db20fd2bSAlexei Starovoitov 
1713db20fd2bSAlexei Starovoitov 	err = 0;
1714db20fd2bSAlexei Starovoitov 
1715db20fd2bSAlexei Starovoitov free_next_key:
171644779a4bSStanislav Fomichev 	kvfree(next_key);
1717db20fd2bSAlexei Starovoitov free_key:
171844779a4bSStanislav Fomichev 	kvfree(key);
1719db20fd2bSAlexei Starovoitov err_put:
1720db20fd2bSAlexei Starovoitov 	fdput(f);
1721db20fd2bSAlexei Starovoitov 	return err;
1722db20fd2bSAlexei Starovoitov }
1723db20fd2bSAlexei Starovoitov 
1724aa2e93b8SBrian Vazquez int generic_map_delete_batch(struct bpf_map *map,
1725aa2e93b8SBrian Vazquez 			     const union bpf_attr *attr,
1726aa2e93b8SBrian Vazquez 			     union bpf_attr __user *uattr)
1727aa2e93b8SBrian Vazquez {
1728aa2e93b8SBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1729aa2e93b8SBrian Vazquez 	u32 cp, max_count;
1730aa2e93b8SBrian Vazquez 	int err = 0;
1731aa2e93b8SBrian Vazquez 	void *key;
1732aa2e93b8SBrian Vazquez 
1733aa2e93b8SBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1734aa2e93b8SBrian Vazquez 		return -EINVAL;
1735aa2e93b8SBrian Vazquez 
1736aa2e93b8SBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1737db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
1738aa2e93b8SBrian Vazquez 		return -EINVAL;
1739aa2e93b8SBrian Vazquez 	}
1740aa2e93b8SBrian Vazquez 
1741aa2e93b8SBrian Vazquez 	max_count = attr->batch.count;
1742aa2e93b8SBrian Vazquez 	if (!max_count)
1743aa2e93b8SBrian Vazquez 		return 0;
1744aa2e93b8SBrian Vazquez 
174506e5c999SHou Tao 	if (put_user(0, &uattr->batch.count))
174606e5c999SHou Tao 		return -EFAULT;
174706e5c999SHou Tao 
174844779a4bSStanislav Fomichev 	key = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
17492e3a94aaSBrian Vazquez 	if (!key)
17502e3a94aaSBrian Vazquez 		return -ENOMEM;
17512e3a94aaSBrian Vazquez 
1752aa2e93b8SBrian Vazquez 	for (cp = 0; cp < max_count; cp++) {
17532e3a94aaSBrian Vazquez 		err = -EFAULT;
17542e3a94aaSBrian Vazquez 		if (copy_from_user(key, keys + cp * map->key_size,
17552e3a94aaSBrian Vazquez 				   map->key_size))
1756aa2e93b8SBrian Vazquez 			break;
1757aa2e93b8SBrian Vazquez 
17589d03ebc7SStanislav Fomichev 		if (bpf_map_is_offloaded(map)) {
1759aa2e93b8SBrian Vazquez 			err = bpf_map_offload_delete_elem(map, key);
1760aa2e93b8SBrian Vazquez 			break;
1761aa2e93b8SBrian Vazquez 		}
1762aa2e93b8SBrian Vazquez 
1763b6e5dae1SThomas Gleixner 		bpf_disable_instrumentation();
1764aa2e93b8SBrian Vazquez 		rcu_read_lock();
1765aa2e93b8SBrian Vazquez 		err = map->ops->map_delete_elem(map, key);
1766aa2e93b8SBrian Vazquez 		rcu_read_unlock();
1767b6e5dae1SThomas Gleixner 		bpf_enable_instrumentation();
1768aa2e93b8SBrian Vazquez 		if (err)
1769aa2e93b8SBrian Vazquez 			break;
177075134f16SEric Dumazet 		cond_resched();
1771aa2e93b8SBrian Vazquez 	}
1772aa2e93b8SBrian Vazquez 	if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp)))
1773aa2e93b8SBrian Vazquez 		err = -EFAULT;
17742e3a94aaSBrian Vazquez 
177544779a4bSStanislav Fomichev 	kvfree(key);
17769087c6ffSEric Dumazet 
1777aa2e93b8SBrian Vazquez 	return err;
1778aa2e93b8SBrian Vazquez }
1779aa2e93b8SBrian Vazquez 
17803af43ba4SHou Tao int generic_map_update_batch(struct bpf_map *map, struct file *map_file,
1781aa2e93b8SBrian Vazquez 			     const union bpf_attr *attr,
1782aa2e93b8SBrian Vazquez 			     union bpf_attr __user *uattr)
1783aa2e93b8SBrian Vazquez {
1784aa2e93b8SBrian Vazquez 	void __user *values = u64_to_user_ptr(attr->batch.values);
1785aa2e93b8SBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1786aa2e93b8SBrian Vazquez 	u32 value_size, cp, max_count;
1787aa2e93b8SBrian Vazquez 	void *key, *value;
1788aa2e93b8SBrian Vazquez 	int err = 0;
1789aa2e93b8SBrian Vazquez 
1790aa2e93b8SBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1791aa2e93b8SBrian Vazquez 		return -EINVAL;
1792aa2e93b8SBrian Vazquez 
1793aa2e93b8SBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1794db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
1795aa2e93b8SBrian Vazquez 		return -EINVAL;
1796aa2e93b8SBrian Vazquez 	}
1797aa2e93b8SBrian Vazquez 
1798aa2e93b8SBrian Vazquez 	value_size = bpf_map_value_size(map);
1799aa2e93b8SBrian Vazquez 
1800aa2e93b8SBrian Vazquez 	max_count = attr->batch.count;
1801aa2e93b8SBrian Vazquez 	if (!max_count)
1802aa2e93b8SBrian Vazquez 		return 0;
1803aa2e93b8SBrian Vazquez 
180406e5c999SHou Tao 	if (put_user(0, &uattr->batch.count))
180506e5c999SHou Tao 		return -EFAULT;
180606e5c999SHou Tao 
180744779a4bSStanislav Fomichev 	key = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
18082e3a94aaSBrian Vazquez 	if (!key)
1809aa2e93b8SBrian Vazquez 		return -ENOMEM;
1810aa2e93b8SBrian Vazquez 
1811f0dce1d9SStanislav Fomichev 	value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN);
18122e3a94aaSBrian Vazquez 	if (!value) {
181344779a4bSStanislav Fomichev 		kvfree(key);
18142e3a94aaSBrian Vazquez 		return -ENOMEM;
1815aa2e93b8SBrian Vazquez 	}
18162e3a94aaSBrian Vazquez 
18172e3a94aaSBrian Vazquez 	for (cp = 0; cp < max_count; cp++) {
1818aa2e93b8SBrian Vazquez 		err = -EFAULT;
18192e3a94aaSBrian Vazquez 		if (copy_from_user(key, keys + cp * map->key_size,
18202e3a94aaSBrian Vazquez 		    map->key_size) ||
18212e3a94aaSBrian Vazquez 		    copy_from_user(value, values + cp * value_size, value_size))
1822aa2e93b8SBrian Vazquez 			break;
1823aa2e93b8SBrian Vazquez 
18243af43ba4SHou Tao 		err = bpf_map_update_value(map, map_file, key, value,
1825aa2e93b8SBrian Vazquez 					   attr->batch.elem_flags);
1826aa2e93b8SBrian Vazquez 
1827aa2e93b8SBrian Vazquez 		if (err)
1828aa2e93b8SBrian Vazquez 			break;
182975134f16SEric Dumazet 		cond_resched();
1830aa2e93b8SBrian Vazquez 	}
1831aa2e93b8SBrian Vazquez 
1832aa2e93b8SBrian Vazquez 	if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp)))
1833aa2e93b8SBrian Vazquez 		err = -EFAULT;
1834aa2e93b8SBrian Vazquez 
1835f0dce1d9SStanislav Fomichev 	kvfree(value);
183644779a4bSStanislav Fomichev 	kvfree(key);
183737ba5b59SHou Tao 
1838aa2e93b8SBrian Vazquez 	return err;
1839aa2e93b8SBrian Vazquez }
1840aa2e93b8SBrian Vazquez 
1841cb4d03abSBrian Vazquez #define MAP_LOOKUP_RETRIES 3
1842cb4d03abSBrian Vazquez 
1843cb4d03abSBrian Vazquez int generic_map_lookup_batch(struct bpf_map *map,
1844cb4d03abSBrian Vazquez 				    const union bpf_attr *attr,
1845cb4d03abSBrian Vazquez 				    union bpf_attr __user *uattr)
1846cb4d03abSBrian Vazquez {
1847cb4d03abSBrian Vazquez 	void __user *uobatch = u64_to_user_ptr(attr->batch.out_batch);
1848cb4d03abSBrian Vazquez 	void __user *ubatch = u64_to_user_ptr(attr->batch.in_batch);
1849cb4d03abSBrian Vazquez 	void __user *values = u64_to_user_ptr(attr->batch.values);
1850cb4d03abSBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1851cb4d03abSBrian Vazquez 	void *buf, *buf_prevkey, *prev_key, *key, *value;
1852cb4d03abSBrian Vazquez 	int err, retry = MAP_LOOKUP_RETRIES;
1853cb4d03abSBrian Vazquez 	u32 value_size, cp, max_count;
1854cb4d03abSBrian Vazquez 
1855cb4d03abSBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1856cb4d03abSBrian Vazquez 		return -EINVAL;
1857cb4d03abSBrian Vazquez 
1858cb4d03abSBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1859db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK))
1860cb4d03abSBrian Vazquez 		return -EINVAL;
1861cb4d03abSBrian Vazquez 
1862cb4d03abSBrian Vazquez 	value_size = bpf_map_value_size(map);
1863cb4d03abSBrian Vazquez 
1864cb4d03abSBrian Vazquez 	max_count = attr->batch.count;
1865cb4d03abSBrian Vazquez 	if (!max_count)
1866cb4d03abSBrian Vazquez 		return 0;
1867cb4d03abSBrian Vazquez 
1868cb4d03abSBrian Vazquez 	if (put_user(0, &uattr->batch.count))
1869cb4d03abSBrian Vazquez 		return -EFAULT;
1870cb4d03abSBrian Vazquez 
187144779a4bSStanislav Fomichev 	buf_prevkey = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
1872cb4d03abSBrian Vazquez 	if (!buf_prevkey)
1873cb4d03abSBrian Vazquez 		return -ENOMEM;
1874cb4d03abSBrian Vazquez 
1875f0dce1d9SStanislav Fomichev 	buf = kvmalloc(map->key_size + value_size, GFP_USER | __GFP_NOWARN);
1876cb4d03abSBrian Vazquez 	if (!buf) {
187744779a4bSStanislav Fomichev 		kvfree(buf_prevkey);
1878cb4d03abSBrian Vazquez 		return -ENOMEM;
1879cb4d03abSBrian Vazquez 	}
1880cb4d03abSBrian Vazquez 
1881cb4d03abSBrian Vazquez 	err = -EFAULT;
1882cb4d03abSBrian Vazquez 	prev_key = NULL;
1883cb4d03abSBrian Vazquez 	if (ubatch && copy_from_user(buf_prevkey, ubatch, map->key_size))
1884cb4d03abSBrian Vazquez 		goto free_buf;
1885cb4d03abSBrian Vazquez 	key = buf;
1886cb4d03abSBrian Vazquez 	value = key + map->key_size;
1887cb4d03abSBrian Vazquez 	if (ubatch)
1888cb4d03abSBrian Vazquez 		prev_key = buf_prevkey;
1889cb4d03abSBrian Vazquez 
1890cb4d03abSBrian Vazquez 	for (cp = 0; cp < max_count;) {
1891cb4d03abSBrian Vazquez 		rcu_read_lock();
1892cb4d03abSBrian Vazquez 		err = map->ops->map_get_next_key(map, prev_key, key);
1893cb4d03abSBrian Vazquez 		rcu_read_unlock();
1894cb4d03abSBrian Vazquez 		if (err)
1895cb4d03abSBrian Vazquez 			break;
1896cb4d03abSBrian Vazquez 		err = bpf_map_copy_value(map, key, value,
1897cb4d03abSBrian Vazquez 					 attr->batch.elem_flags);
1898cb4d03abSBrian Vazquez 
1899cb4d03abSBrian Vazquez 		if (err == -ENOENT) {
1900cb4d03abSBrian Vazquez 			if (retry) {
1901cb4d03abSBrian Vazquez 				retry--;
1902cb4d03abSBrian Vazquez 				continue;
1903cb4d03abSBrian Vazquez 			}
1904cb4d03abSBrian Vazquez 			err = -EINTR;
1905cb4d03abSBrian Vazquez 			break;
1906cb4d03abSBrian Vazquez 		}
1907cb4d03abSBrian Vazquez 
1908cb4d03abSBrian Vazquez 		if (err)
1909cb4d03abSBrian Vazquez 			goto free_buf;
1910cb4d03abSBrian Vazquez 
1911cb4d03abSBrian Vazquez 		if (copy_to_user(keys + cp * map->key_size, key,
1912cb4d03abSBrian Vazquez 				 map->key_size)) {
1913cb4d03abSBrian Vazquez 			err = -EFAULT;
1914cb4d03abSBrian Vazquez 			goto free_buf;
1915cb4d03abSBrian Vazquez 		}
1916cb4d03abSBrian Vazquez 		if (copy_to_user(values + cp * value_size, value, value_size)) {
1917cb4d03abSBrian Vazquez 			err = -EFAULT;
1918cb4d03abSBrian Vazquez 			goto free_buf;
1919cb4d03abSBrian Vazquez 		}
1920cb4d03abSBrian Vazquez 
1921cb4d03abSBrian Vazquez 		if (!prev_key)
1922cb4d03abSBrian Vazquez 			prev_key = buf_prevkey;
1923cb4d03abSBrian Vazquez 
1924cb4d03abSBrian Vazquez 		swap(prev_key, key);
1925cb4d03abSBrian Vazquez 		retry = MAP_LOOKUP_RETRIES;
1926cb4d03abSBrian Vazquez 		cp++;
192775134f16SEric Dumazet 		cond_resched();
1928cb4d03abSBrian Vazquez 	}
1929cb4d03abSBrian Vazquez 
1930cb4d03abSBrian Vazquez 	if (err == -EFAULT)
1931cb4d03abSBrian Vazquez 		goto free_buf;
1932cb4d03abSBrian Vazquez 
1933cb4d03abSBrian Vazquez 	if ((copy_to_user(&uattr->batch.count, &cp, sizeof(cp)) ||
1934cb4d03abSBrian Vazquez 		    (cp && copy_to_user(uobatch, prev_key, map->key_size))))
1935cb4d03abSBrian Vazquez 		err = -EFAULT;
1936cb4d03abSBrian Vazquez 
1937cb4d03abSBrian Vazquez free_buf:
193844779a4bSStanislav Fomichev 	kvfree(buf_prevkey);
1939f0dce1d9SStanislav Fomichev 	kvfree(buf);
1940cb4d03abSBrian Vazquez 	return err;
1941cb4d03abSBrian Vazquez }
1942cb4d03abSBrian Vazquez 
19433e87f192SDenis Salopek #define BPF_MAP_LOOKUP_AND_DELETE_ELEM_LAST_FIELD flags
1944bd513cd0SMauricio Vasquez B 
1945bd513cd0SMauricio Vasquez B static int map_lookup_and_delete_elem(union bpf_attr *attr)
1946bd513cd0SMauricio Vasquez B {
1947bd513cd0SMauricio Vasquez B 	void __user *ukey = u64_to_user_ptr(attr->key);
1948bd513cd0SMauricio Vasquez B 	void __user *uvalue = u64_to_user_ptr(attr->value);
1949bd513cd0SMauricio Vasquez B 	int ufd = attr->map_fd;
1950bd513cd0SMauricio Vasquez B 	struct bpf_map *map;
1951540fefc0SAlexei Starovoitov 	void *key, *value;
1952bd513cd0SMauricio Vasquez B 	u32 value_size;
1953bd513cd0SMauricio Vasquez B 	struct fd f;
1954bd513cd0SMauricio Vasquez B 	int err;
1955bd513cd0SMauricio Vasquez B 
1956bd513cd0SMauricio Vasquez B 	if (CHECK_ATTR(BPF_MAP_LOOKUP_AND_DELETE_ELEM))
1957bd513cd0SMauricio Vasquez B 		return -EINVAL;
1958bd513cd0SMauricio Vasquez B 
19593e87f192SDenis Salopek 	if (attr->flags & ~BPF_F_LOCK)
19603e87f192SDenis Salopek 		return -EINVAL;
19613e87f192SDenis Salopek 
1962bd513cd0SMauricio Vasquez B 	f = fdget(ufd);
1963bd513cd0SMauricio Vasquez B 	map = __bpf_map_get(f);
1964bd513cd0SMauricio Vasquez B 	if (IS_ERR(map))
1965bd513cd0SMauricio Vasquez B 		return PTR_ERR(map);
1966353050beSDaniel Borkmann 	bpf_map_write_active_inc(map);
19671ea0f912SAnton Protopopov 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ) ||
19681ea0f912SAnton Protopopov 	    !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
1969bd513cd0SMauricio Vasquez B 		err = -EPERM;
1970bd513cd0SMauricio Vasquez B 		goto err_put;
1971bd513cd0SMauricio Vasquez B 	}
1972bd513cd0SMauricio Vasquez B 
19733e87f192SDenis Salopek 	if (attr->flags &&
19743e87f192SDenis Salopek 	    (map->map_type == BPF_MAP_TYPE_QUEUE ||
19753e87f192SDenis Salopek 	     map->map_type == BPF_MAP_TYPE_STACK)) {
19763e87f192SDenis Salopek 		err = -EINVAL;
19773e87f192SDenis Salopek 		goto err_put;
19783e87f192SDenis Salopek 	}
19793e87f192SDenis Salopek 
19803e87f192SDenis Salopek 	if ((attr->flags & BPF_F_LOCK) &&
1981db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
19823e87f192SDenis Salopek 		err = -EINVAL;
19833e87f192SDenis Salopek 		goto err_put;
19843e87f192SDenis Salopek 	}
19853e87f192SDenis Salopek 
1986bd513cd0SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
1987bd513cd0SMauricio Vasquez B 	if (IS_ERR(key)) {
1988bd513cd0SMauricio Vasquez B 		err = PTR_ERR(key);
1989bd513cd0SMauricio Vasquez B 		goto err_put;
1990bd513cd0SMauricio Vasquez B 	}
1991bd513cd0SMauricio Vasquez B 
19923e87f192SDenis Salopek 	value_size = bpf_map_value_size(map);
1993bd513cd0SMauricio Vasquez B 
1994bd513cd0SMauricio Vasquez B 	err = -ENOMEM;
1995f0dce1d9SStanislav Fomichev 	value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN);
1996bd513cd0SMauricio Vasquez B 	if (!value)
1997bd513cd0SMauricio Vasquez B 		goto free_key;
1998bd513cd0SMauricio Vasquez B 
19993e87f192SDenis Salopek 	err = -ENOTSUPP;
2000bd513cd0SMauricio Vasquez B 	if (map->map_type == BPF_MAP_TYPE_QUEUE ||
2001bd513cd0SMauricio Vasquez B 	    map->map_type == BPF_MAP_TYPE_STACK) {
2002bd513cd0SMauricio Vasquez B 		err = map->ops->map_pop_elem(map, value);
20033e87f192SDenis Salopek 	} else if (map->map_type == BPF_MAP_TYPE_HASH ||
20043e87f192SDenis Salopek 		   map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
20053e87f192SDenis Salopek 		   map->map_type == BPF_MAP_TYPE_LRU_HASH ||
20063e87f192SDenis Salopek 		   map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
20079d03ebc7SStanislav Fomichev 		if (!bpf_map_is_offloaded(map)) {
20083e87f192SDenis Salopek 			bpf_disable_instrumentation();
20093e87f192SDenis Salopek 			rcu_read_lock();
20103e87f192SDenis Salopek 			err = map->ops->map_lookup_and_delete_elem(map, key, value, attr->flags);
20113e87f192SDenis Salopek 			rcu_read_unlock();
20123e87f192SDenis Salopek 			bpf_enable_instrumentation();
20133e87f192SDenis Salopek 		}
2014bd513cd0SMauricio Vasquez B 	}
2015bd513cd0SMauricio Vasquez B 
2016bd513cd0SMauricio Vasquez B 	if (err)
2017bd513cd0SMauricio Vasquez B 		goto free_value;
2018bd513cd0SMauricio Vasquez B 
20197f645462SWei Yongjun 	if (copy_to_user(uvalue, value, value_size) != 0) {
20207f645462SWei Yongjun 		err = -EFAULT;
2021bd513cd0SMauricio Vasquez B 		goto free_value;
20227f645462SWei Yongjun 	}
2023bd513cd0SMauricio Vasquez B 
2024bd513cd0SMauricio Vasquez B 	err = 0;
2025bd513cd0SMauricio Vasquez B 
2026bd513cd0SMauricio Vasquez B free_value:
2027f0dce1d9SStanislav Fomichev 	kvfree(value);
2028bd513cd0SMauricio Vasquez B free_key:
202944779a4bSStanislav Fomichev 	kvfree(key);
2030bd513cd0SMauricio Vasquez B err_put:
2031353050beSDaniel Borkmann 	bpf_map_write_active_dec(map);
2032bd513cd0SMauricio Vasquez B 	fdput(f);
2033bd513cd0SMauricio Vasquez B 	return err;
2034bd513cd0SMauricio Vasquez B }
2035bd513cd0SMauricio Vasquez B 
203687df15deSDaniel Borkmann #define BPF_MAP_FREEZE_LAST_FIELD map_fd
203787df15deSDaniel Borkmann 
203887df15deSDaniel Borkmann static int map_freeze(const union bpf_attr *attr)
203987df15deSDaniel Borkmann {
204087df15deSDaniel Borkmann 	int err = 0, ufd = attr->map_fd;
204187df15deSDaniel Borkmann 	struct bpf_map *map;
204287df15deSDaniel Borkmann 	struct fd f;
204387df15deSDaniel Borkmann 
204487df15deSDaniel Borkmann 	if (CHECK_ATTR(BPF_MAP_FREEZE))
204587df15deSDaniel Borkmann 		return -EINVAL;
204687df15deSDaniel Borkmann 
204787df15deSDaniel Borkmann 	f = fdget(ufd);
204887df15deSDaniel Borkmann 	map = __bpf_map_get(f);
204987df15deSDaniel Borkmann 	if (IS_ERR(map))
205087df15deSDaniel Borkmann 		return PTR_ERR(map);
2051fc970227SAndrii Nakryiko 
2052db559117SKumar Kartikeya Dwivedi 	if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS || !IS_ERR_OR_NULL(map->record)) {
2053849b4d94SMartin KaFai Lau 		fdput(f);
2054849b4d94SMartin KaFai Lau 		return -ENOTSUPP;
2055849b4d94SMartin KaFai Lau 	}
2056849b4d94SMartin KaFai Lau 
2057c4c84f6fSAndrii Nakryiko 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
20584266f41fSDaniel Borkmann 		fdput(f);
20594266f41fSDaniel Borkmann 		return -EPERM;
2060c4c84f6fSAndrii Nakryiko 	}
2061c4c84f6fSAndrii Nakryiko 
2062fc970227SAndrii Nakryiko 	mutex_lock(&map->freeze_mutex);
2063353050beSDaniel Borkmann 	if (bpf_map_write_active(map)) {
2064fc970227SAndrii Nakryiko 		err = -EBUSY;
2065fc970227SAndrii Nakryiko 		goto err_put;
2066fc970227SAndrii Nakryiko 	}
206787df15deSDaniel Borkmann 	if (READ_ONCE(map->frozen)) {
206887df15deSDaniel Borkmann 		err = -EBUSY;
206987df15deSDaniel Borkmann 		goto err_put;
207087df15deSDaniel Borkmann 	}
207187df15deSDaniel Borkmann 
207287df15deSDaniel Borkmann 	WRITE_ONCE(map->frozen, true);
207387df15deSDaniel Borkmann err_put:
2074fc970227SAndrii Nakryiko 	mutex_unlock(&map->freeze_mutex);
207587df15deSDaniel Borkmann 	fdput(f);
207687df15deSDaniel Borkmann 	return err;
207787df15deSDaniel Borkmann }
207887df15deSDaniel Borkmann 
20797de16e3aSJakub Kicinski static const struct bpf_prog_ops * const bpf_prog_types[] = {
208091cc1a99SAlexei Starovoitov #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \
20817de16e3aSJakub Kicinski 	[_id] = & _name ## _prog_ops,
20827de16e3aSJakub Kicinski #define BPF_MAP_TYPE(_id, _ops)
2083f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name)
20847de16e3aSJakub Kicinski #include <linux/bpf_types.h>
20857de16e3aSJakub Kicinski #undef BPF_PROG_TYPE
20867de16e3aSJakub Kicinski #undef BPF_MAP_TYPE
2087f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE
20887de16e3aSJakub Kicinski };
20897de16e3aSJakub Kicinski 
209009756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
209109756af4SAlexei Starovoitov {
2092d0f1a451SDaniel Borkmann 	const struct bpf_prog_ops *ops;
2093d0f1a451SDaniel Borkmann 
2094d0f1a451SDaniel Borkmann 	if (type >= ARRAY_SIZE(bpf_prog_types))
2095d0f1a451SDaniel Borkmann 		return -EINVAL;
2096d0f1a451SDaniel Borkmann 	type = array_index_nospec(type, ARRAY_SIZE(bpf_prog_types));
2097d0f1a451SDaniel Borkmann 	ops = bpf_prog_types[type];
2098d0f1a451SDaniel Borkmann 	if (!ops)
2099be9370a7SJohannes Berg 		return -EINVAL;
210009756af4SAlexei Starovoitov 
21019d03ebc7SStanislav Fomichev 	if (!bpf_prog_is_offloaded(prog->aux))
2102d0f1a451SDaniel Borkmann 		prog->aux->ops = ops;
2103ab3f0063SJakub Kicinski 	else
2104ab3f0063SJakub Kicinski 		prog->aux->ops = &bpf_offload_prog_ops;
210524701eceSDaniel Borkmann 	prog->type = type;
210609756af4SAlexei Starovoitov 	return 0;
210709756af4SAlexei Starovoitov }
210809756af4SAlexei Starovoitov 
2109bae141f5SDaniel Borkmann enum bpf_audit {
2110bae141f5SDaniel Borkmann 	BPF_AUDIT_LOAD,
2111bae141f5SDaniel Borkmann 	BPF_AUDIT_UNLOAD,
2112bae141f5SDaniel Borkmann 	BPF_AUDIT_MAX,
2113bae141f5SDaniel Borkmann };
2114bae141f5SDaniel Borkmann 
2115bae141f5SDaniel Borkmann static const char * const bpf_audit_str[BPF_AUDIT_MAX] = {
2116bae141f5SDaniel Borkmann 	[BPF_AUDIT_LOAD]   = "LOAD",
2117bae141f5SDaniel Borkmann 	[BPF_AUDIT_UNLOAD] = "UNLOAD",
2118bae141f5SDaniel Borkmann };
2119bae141f5SDaniel Borkmann 
2120bae141f5SDaniel Borkmann static void bpf_audit_prog(const struct bpf_prog *prog, unsigned int op)
2121bae141f5SDaniel Borkmann {
2122bae141f5SDaniel Borkmann 	struct audit_context *ctx = NULL;
2123bae141f5SDaniel Borkmann 	struct audit_buffer *ab;
2124bae141f5SDaniel Borkmann 
2125bae141f5SDaniel Borkmann 	if (WARN_ON_ONCE(op >= BPF_AUDIT_MAX))
2126bae141f5SDaniel Borkmann 		return;
2127bae141f5SDaniel Borkmann 	if (audit_enabled == AUDIT_OFF)
2128bae141f5SDaniel Borkmann 		return;
2129ef01f4e2SPaul Moore 	if (!in_irq() && !irqs_disabled())
2130bae141f5SDaniel Borkmann 		ctx = audit_context();
2131bae141f5SDaniel Borkmann 	ab = audit_log_start(ctx, GFP_ATOMIC, AUDIT_BPF);
2132bae141f5SDaniel Borkmann 	if (unlikely(!ab))
2133bae141f5SDaniel Borkmann 		return;
2134bae141f5SDaniel Borkmann 	audit_log_format(ab, "prog-id=%u op=%s",
2135bae141f5SDaniel Borkmann 			 prog->aux->id, bpf_audit_str[op]);
2136bae141f5SDaniel Borkmann 	audit_log_end(ab);
2137bae141f5SDaniel Borkmann }
2138bae141f5SDaniel Borkmann 
2139dc4bb0e2SMartin KaFai Lau static int bpf_prog_alloc_id(struct bpf_prog *prog)
2140dc4bb0e2SMartin KaFai Lau {
2141dc4bb0e2SMartin KaFai Lau 	int id;
2142dc4bb0e2SMartin KaFai Lau 
2143b76354cdSShaohua Li 	idr_preload(GFP_KERNEL);
2144dc4bb0e2SMartin KaFai Lau 	spin_lock_bh(&prog_idr_lock);
2145dc4bb0e2SMartin KaFai Lau 	id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC);
2146dc4bb0e2SMartin KaFai Lau 	if (id > 0)
2147dc4bb0e2SMartin KaFai Lau 		prog->aux->id = id;
2148dc4bb0e2SMartin KaFai Lau 	spin_unlock_bh(&prog_idr_lock);
2149b76354cdSShaohua Li 	idr_preload_end();
2150dc4bb0e2SMartin KaFai Lau 
2151dc4bb0e2SMartin KaFai Lau 	/* id is in [1, INT_MAX) */
2152dc4bb0e2SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
2153dc4bb0e2SMartin KaFai Lau 		return -ENOSPC;
2154dc4bb0e2SMartin KaFai Lau 
2155dc4bb0e2SMartin KaFai Lau 	return id > 0 ? 0 : id;
2156dc4bb0e2SMartin KaFai Lau }
2157dc4bb0e2SMartin KaFai Lau 
2158e7895f01SPaul Moore void bpf_prog_free_id(struct bpf_prog *prog)
2159dc4bb0e2SMartin KaFai Lau {
2160d809e134SAlexei Starovoitov 	unsigned long flags;
2161d809e134SAlexei Starovoitov 
2162ad8ad79fSJakub Kicinski 	/* cBPF to eBPF migrations are currently not in the idr store.
2163ad8ad79fSJakub Kicinski 	 * Offloaded programs are removed from the store when their device
2164ad8ad79fSJakub Kicinski 	 * disappears - even if someone grabs an fd to them they are unusable,
2165ad8ad79fSJakub Kicinski 	 * simply waiting for refcnt to drop to be freed.
2166ad8ad79fSJakub Kicinski 	 */
2167dc4bb0e2SMartin KaFai Lau 	if (!prog->aux->id)
2168dc4bb0e2SMartin KaFai Lau 		return;
2169dc4bb0e2SMartin KaFai Lau 
2170d809e134SAlexei Starovoitov 	spin_lock_irqsave(&prog_idr_lock, flags);
2171dc4bb0e2SMartin KaFai Lau 	idr_remove(&prog_idr, prog->aux->id);
2172ad8ad79fSJakub Kicinski 	prog->aux->id = 0;
2173d809e134SAlexei Starovoitov 	spin_unlock_irqrestore(&prog_idr_lock, flags);
2174dc4bb0e2SMartin KaFai Lau }
2175dc4bb0e2SMartin KaFai Lau 
21761aacde3dSDaniel Borkmann static void __bpf_prog_put_rcu(struct rcu_head *rcu)
2177abf2e7d6SAlexei Starovoitov {
2178abf2e7d6SAlexei Starovoitov 	struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
2179abf2e7d6SAlexei Starovoitov 
21803b4d9eb2SDaniel Borkmann 	kvfree(aux->func_info);
21818c1b6e69SAlexei Starovoitov 	kfree(aux->func_info_aux);
21823ac1f01bSRoman Gushchin 	free_uid(aux->user);
2183d17aff80SAndrii Nakryiko 	security_bpf_prog_free(aux);
2184abf2e7d6SAlexei Starovoitov 	bpf_prog_free(aux->prog);
2185abf2e7d6SAlexei Starovoitov }
2186abf2e7d6SAlexei Starovoitov 
2187cd7455f1SDaniel Borkmann static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
2188cd7455f1SDaniel Borkmann {
2189cd7455f1SDaniel Borkmann 	bpf_prog_kallsyms_del_all(prog);
2190cd7455f1SDaniel Borkmann 	btf_put(prog->aux->btf);
219131bf1dbcSViktor Malik 	module_put(prog->aux->mod);
2192e16301fbSMartin KaFai Lau 	kvfree(prog->aux->jited_linfo);
2193e16301fbSMartin KaFai Lau 	kvfree(prog->aux->linfo);
2194e6ac2450SMartin KaFai Lau 	kfree(prog->aux->kfunc_tab);
219522dc4a0fSAndrii Nakryiko 	if (prog->aux->attach_btf)
219622dc4a0fSAndrii Nakryiko 		btf_put(prog->aux->attach_btf);
2197cd7455f1SDaniel Borkmann 
21981e6c62a8SAlexei Starovoitov 	if (deferred) {
21991e6c62a8SAlexei Starovoitov 		if (prog->aux->sleepable)
22001e6c62a8SAlexei Starovoitov 			call_rcu_tasks_trace(&prog->aux->rcu, __bpf_prog_put_rcu);
2201cd7455f1SDaniel Borkmann 		else
22021e6c62a8SAlexei Starovoitov 			call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
22031e6c62a8SAlexei Starovoitov 	} else {
2204cd7455f1SDaniel Borkmann 		__bpf_prog_put_rcu(&prog->aux->rcu);
2205cd7455f1SDaniel Borkmann 	}
22061e6c62a8SAlexei Starovoitov }
2207cd7455f1SDaniel Borkmann 
2208d809e134SAlexei Starovoitov static void bpf_prog_put_deferred(struct work_struct *work)
220909756af4SAlexei Starovoitov {
2210d809e134SAlexei Starovoitov 	struct bpf_prog_aux *aux;
2211d809e134SAlexei Starovoitov 	struct bpf_prog *prog;
2212d809e134SAlexei Starovoitov 
2213d809e134SAlexei Starovoitov 	aux = container_of(work, struct bpf_prog_aux, work);
2214d809e134SAlexei Starovoitov 	prog = aux->prog;
22156ee52e2aSSong Liu 	perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0);
2216bae141f5SDaniel Borkmann 	bpf_audit_prog(prog, BPF_AUDIT_UNLOAD);
2217e7895f01SPaul Moore 	bpf_prog_free_id(prog);
2218d809e134SAlexei Starovoitov 	__bpf_prog_put_noref(prog, true);
2219d809e134SAlexei Starovoitov }
2220d809e134SAlexei Starovoitov 
2221e7895f01SPaul Moore static void __bpf_prog_put(struct bpf_prog *prog)
2222d809e134SAlexei Starovoitov {
2223d809e134SAlexei Starovoitov 	struct bpf_prog_aux *aux = prog->aux;
2224d809e134SAlexei Starovoitov 
2225d809e134SAlexei Starovoitov 	if (atomic64_dec_and_test(&aux->refcnt)) {
2226d809e134SAlexei Starovoitov 		if (in_irq() || irqs_disabled()) {
2227d809e134SAlexei Starovoitov 			INIT_WORK(&aux->work, bpf_prog_put_deferred);
2228d809e134SAlexei Starovoitov 			schedule_work(&aux->work);
2229d809e134SAlexei Starovoitov 		} else {
2230d809e134SAlexei Starovoitov 			bpf_prog_put_deferred(&aux->work);
2231d809e134SAlexei Starovoitov 		}
223209756af4SAlexei Starovoitov 	}
2233a67edbf4SDaniel Borkmann }
2234b16d9aa4SMartin KaFai Lau 
2235b16d9aa4SMartin KaFai Lau void bpf_prog_put(struct bpf_prog *prog)
2236b16d9aa4SMartin KaFai Lau {
2237e7895f01SPaul Moore 	__bpf_prog_put(prog);
2238b16d9aa4SMartin KaFai Lau }
2239e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put);
224009756af4SAlexei Starovoitov 
224109756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp)
224209756af4SAlexei Starovoitov {
224309756af4SAlexei Starovoitov 	struct bpf_prog *prog = filp->private_data;
224409756af4SAlexei Starovoitov 
22451aacde3dSDaniel Borkmann 	bpf_prog_put(prog);
224609756af4SAlexei Starovoitov 	return 0;
224709756af4SAlexei Starovoitov }
224809756af4SAlexei Starovoitov 
224961a0abaeSEric Dumazet struct bpf_prog_kstats {
225061a0abaeSEric Dumazet 	u64 nsecs;
225161a0abaeSEric Dumazet 	u64 cnt;
225261a0abaeSEric Dumazet 	u64 misses;
225361a0abaeSEric Dumazet };
225461a0abaeSEric Dumazet 
225505b24ff9SJiri Olsa void notrace bpf_prog_inc_misses_counter(struct bpf_prog *prog)
225605b24ff9SJiri Olsa {
225705b24ff9SJiri Olsa 	struct bpf_prog_stats *stats;
225805b24ff9SJiri Olsa 	unsigned int flags;
225905b24ff9SJiri Olsa 
226005b24ff9SJiri Olsa 	stats = this_cpu_ptr(prog->stats);
226105b24ff9SJiri Olsa 	flags = u64_stats_update_begin_irqsave(&stats->syncp);
226205b24ff9SJiri Olsa 	u64_stats_inc(&stats->misses);
226305b24ff9SJiri Olsa 	u64_stats_update_end_irqrestore(&stats->syncp, flags);
226405b24ff9SJiri Olsa }
226505b24ff9SJiri Olsa 
2266492ecee8SAlexei Starovoitov static void bpf_prog_get_stats(const struct bpf_prog *prog,
226761a0abaeSEric Dumazet 			       struct bpf_prog_kstats *stats)
2268492ecee8SAlexei Starovoitov {
22699ed9e9baSAlexei Starovoitov 	u64 nsecs = 0, cnt = 0, misses = 0;
2270492ecee8SAlexei Starovoitov 	int cpu;
2271492ecee8SAlexei Starovoitov 
2272492ecee8SAlexei Starovoitov 	for_each_possible_cpu(cpu) {
2273492ecee8SAlexei Starovoitov 		const struct bpf_prog_stats *st;
2274492ecee8SAlexei Starovoitov 		unsigned int start;
22759ed9e9baSAlexei Starovoitov 		u64 tnsecs, tcnt, tmisses;
2276492ecee8SAlexei Starovoitov 
2277700d4796SAlexei Starovoitov 		st = per_cpu_ptr(prog->stats, cpu);
2278492ecee8SAlexei Starovoitov 		do {
227997c4090bSThomas Gleixner 			start = u64_stats_fetch_begin(&st->syncp);
228061a0abaeSEric Dumazet 			tnsecs = u64_stats_read(&st->nsecs);
228161a0abaeSEric Dumazet 			tcnt = u64_stats_read(&st->cnt);
228261a0abaeSEric Dumazet 			tmisses = u64_stats_read(&st->misses);
228397c4090bSThomas Gleixner 		} while (u64_stats_fetch_retry(&st->syncp, start));
2284492ecee8SAlexei Starovoitov 		nsecs += tnsecs;
2285492ecee8SAlexei Starovoitov 		cnt += tcnt;
22869ed9e9baSAlexei Starovoitov 		misses += tmisses;
2287492ecee8SAlexei Starovoitov 	}
2288492ecee8SAlexei Starovoitov 	stats->nsecs = nsecs;
2289492ecee8SAlexei Starovoitov 	stats->cnt = cnt;
22909ed9e9baSAlexei Starovoitov 	stats->misses = misses;
2291492ecee8SAlexei Starovoitov }
2292492ecee8SAlexei Starovoitov 
22937bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
22947bd509e3SDaniel Borkmann static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp)
22957bd509e3SDaniel Borkmann {
22967bd509e3SDaniel Borkmann 	const struct bpf_prog *prog = filp->private_data;
2297f1f7714eSDaniel Borkmann 	char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
229861a0abaeSEric Dumazet 	struct bpf_prog_kstats stats;
22997bd509e3SDaniel Borkmann 
2300492ecee8SAlexei Starovoitov 	bpf_prog_get_stats(prog, &stats);
2301f1f7714eSDaniel Borkmann 	bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
23027bd509e3SDaniel Borkmann 	seq_printf(m,
23037bd509e3SDaniel Borkmann 		   "prog_type:\t%u\n"
23047bd509e3SDaniel Borkmann 		   "prog_jited:\t%u\n"
2305f1f7714eSDaniel Borkmann 		   "prog_tag:\t%s\n"
23064316b409SDaniel Borkmann 		   "memlock:\t%llu\n"
2307492ecee8SAlexei Starovoitov 		   "prog_id:\t%u\n"
2308492ecee8SAlexei Starovoitov 		   "run_time_ns:\t%llu\n"
23099ed9e9baSAlexei Starovoitov 		   "run_cnt:\t%llu\n"
2310aba64c7dSDave Marchevsky 		   "recursion_misses:\t%llu\n"
2311aba64c7dSDave Marchevsky 		   "verified_insns:\t%u\n",
23127bd509e3SDaniel Borkmann 		   prog->type,
23137bd509e3SDaniel Borkmann 		   prog->jited,
2314f1f7714eSDaniel Borkmann 		   prog_tag,
23154316b409SDaniel Borkmann 		   prog->pages * 1ULL << PAGE_SHIFT,
2316492ecee8SAlexei Starovoitov 		   prog->aux->id,
2317492ecee8SAlexei Starovoitov 		   stats.nsecs,
23189ed9e9baSAlexei Starovoitov 		   stats.cnt,
2319aba64c7dSDave Marchevsky 		   stats.misses,
2320aba64c7dSDave Marchevsky 		   prog->aux->verified_insns);
23217bd509e3SDaniel Borkmann }
23227bd509e3SDaniel Borkmann #endif
23237bd509e3SDaniel Borkmann 
2324f66e448cSChenbo Feng const struct file_operations bpf_prog_fops = {
23257bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
23267bd509e3SDaniel Borkmann 	.show_fdinfo	= bpf_prog_show_fdinfo,
23277bd509e3SDaniel Borkmann #endif
232809756af4SAlexei Starovoitov 	.release	= bpf_prog_release,
23296e71b04aSChenbo Feng 	.read		= bpf_dummy_read,
23306e71b04aSChenbo Feng 	.write		= bpf_dummy_write,
233109756af4SAlexei Starovoitov };
233209756af4SAlexei Starovoitov 
2333b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog)
2334aa79781bSDaniel Borkmann {
2335afdb09c7SChenbo Feng 	int ret;
2336afdb09c7SChenbo Feng 
2337afdb09c7SChenbo Feng 	ret = security_bpf_prog(prog);
2338afdb09c7SChenbo Feng 	if (ret < 0)
2339afdb09c7SChenbo Feng 		return ret;
2340afdb09c7SChenbo Feng 
2341aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog,
2342aa79781bSDaniel Borkmann 				O_RDWR | O_CLOEXEC);
2343aa79781bSDaniel Borkmann }
2344aa79781bSDaniel Borkmann 
2345113214beSDaniel Borkmann static struct bpf_prog *____bpf_prog_get(struct fd f)
234609756af4SAlexei Starovoitov {
234709756af4SAlexei Starovoitov 	if (!f.file)
234809756af4SAlexei Starovoitov 		return ERR_PTR(-EBADF);
234909756af4SAlexei Starovoitov 	if (f.file->f_op != &bpf_prog_fops) {
235009756af4SAlexei Starovoitov 		fdput(f);
235109756af4SAlexei Starovoitov 		return ERR_PTR(-EINVAL);
235209756af4SAlexei Starovoitov 	}
235309756af4SAlexei Starovoitov 
2354c2101297SDaniel Borkmann 	return f.file->private_data;
235509756af4SAlexei Starovoitov }
235609756af4SAlexei Starovoitov 
235785192dbfSAndrii Nakryiko void bpf_prog_add(struct bpf_prog *prog, int i)
235892117d84SAlexei Starovoitov {
235985192dbfSAndrii Nakryiko 	atomic64_add(i, &prog->aux->refcnt);
236092117d84SAlexei Starovoitov }
236159d3656dSBrenden Blanco EXPORT_SYMBOL_GPL(bpf_prog_add);
236259d3656dSBrenden Blanco 
2363c540594fSDaniel Borkmann void bpf_prog_sub(struct bpf_prog *prog, int i)
2364c540594fSDaniel Borkmann {
2365c540594fSDaniel Borkmann 	/* Only to be used for undoing previous bpf_prog_add() in some
2366c540594fSDaniel Borkmann 	 * error path. We still know that another entity in our call
2367c540594fSDaniel Borkmann 	 * path holds a reference to the program, thus atomic_sub() can
2368c540594fSDaniel Borkmann 	 * be safely used in such cases!
2369c540594fSDaniel Borkmann 	 */
237085192dbfSAndrii Nakryiko 	WARN_ON(atomic64_sub_return(i, &prog->aux->refcnt) == 0);
2371c540594fSDaniel Borkmann }
2372c540594fSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_sub);
2373c540594fSDaniel Borkmann 
237485192dbfSAndrii Nakryiko void bpf_prog_inc(struct bpf_prog *prog)
237559d3656dSBrenden Blanco {
237685192dbfSAndrii Nakryiko 	atomic64_inc(&prog->aux->refcnt);
237759d3656dSBrenden Blanco }
237897bc402dSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_inc);
237992117d84SAlexei Starovoitov 
2380b16d9aa4SMartin KaFai Lau /* prog_idr_lock should have been held */
2381a6f6df69SJohn Fastabend struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog)
2382b16d9aa4SMartin KaFai Lau {
2383b16d9aa4SMartin KaFai Lau 	int refold;
2384b16d9aa4SMartin KaFai Lau 
238585192dbfSAndrii Nakryiko 	refold = atomic64_fetch_add_unless(&prog->aux->refcnt, 1, 0);
2386b16d9aa4SMartin KaFai Lau 
2387b16d9aa4SMartin KaFai Lau 	if (!refold)
2388b16d9aa4SMartin KaFai Lau 		return ERR_PTR(-ENOENT);
2389b16d9aa4SMartin KaFai Lau 
2390b16d9aa4SMartin KaFai Lau 	return prog;
2391b16d9aa4SMartin KaFai Lau }
2392a6f6df69SJohn Fastabend EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero);
2393b16d9aa4SMartin KaFai Lau 
2394040ee692SAl Viro bool bpf_prog_get_ok(struct bpf_prog *prog,
2395288b3de5SJakub Kicinski 			    enum bpf_prog_type *attach_type, bool attach_drv)
2396248f346fSJakub Kicinski {
2397288b3de5SJakub Kicinski 	/* not an attachment, just a refcount inc, always allow */
2398288b3de5SJakub Kicinski 	if (!attach_type)
2399288b3de5SJakub Kicinski 		return true;
2400248f346fSJakub Kicinski 
2401248f346fSJakub Kicinski 	if (prog->type != *attach_type)
2402248f346fSJakub Kicinski 		return false;
24039d03ebc7SStanislav Fomichev 	if (bpf_prog_is_offloaded(prog->aux) && !attach_drv)
2404248f346fSJakub Kicinski 		return false;
2405248f346fSJakub Kicinski 
2406248f346fSJakub Kicinski 	return true;
2407248f346fSJakub Kicinski }
2408248f346fSJakub Kicinski 
2409248f346fSJakub Kicinski static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type,
2410288b3de5SJakub Kicinski 				       bool attach_drv)
241109756af4SAlexei Starovoitov {
241209756af4SAlexei Starovoitov 	struct fd f = fdget(ufd);
241309756af4SAlexei Starovoitov 	struct bpf_prog *prog;
241409756af4SAlexei Starovoitov 
2415113214beSDaniel Borkmann 	prog = ____bpf_prog_get(f);
241609756af4SAlexei Starovoitov 	if (IS_ERR(prog))
241709756af4SAlexei Starovoitov 		return prog;
2418288b3de5SJakub Kicinski 	if (!bpf_prog_get_ok(prog, attach_type, attach_drv)) {
2419113214beSDaniel Borkmann 		prog = ERR_PTR(-EINVAL);
2420113214beSDaniel Borkmann 		goto out;
2421113214beSDaniel Borkmann 	}
242209756af4SAlexei Starovoitov 
242385192dbfSAndrii Nakryiko 	bpf_prog_inc(prog);
2424113214beSDaniel Borkmann out:
242509756af4SAlexei Starovoitov 	fdput(f);
242609756af4SAlexei Starovoitov 	return prog;
242709756af4SAlexei Starovoitov }
2428113214beSDaniel Borkmann 
2429113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get(u32 ufd)
2430113214beSDaniel Borkmann {
2431288b3de5SJakub Kicinski 	return __bpf_prog_get(ufd, NULL, false);
2432113214beSDaniel Borkmann }
2433113214beSDaniel Borkmann 
2434248f346fSJakub Kicinski struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type,
2435288b3de5SJakub Kicinski 				       bool attach_drv)
2436248f346fSJakub Kicinski {
24374d220ed0SAlexei Starovoitov 	return __bpf_prog_get(ufd, &type, attach_drv);
2438248f346fSJakub Kicinski }
24396c8dfe21SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev);
2440248f346fSJakub Kicinski 
2441aac3fc32SAndrey Ignatov /* Initially all BPF programs could be loaded w/o specifying
2442aac3fc32SAndrey Ignatov  * expected_attach_type. Later for some of them specifying expected_attach_type
2443aac3fc32SAndrey Ignatov  * at load time became required so that program could be validated properly.
2444aac3fc32SAndrey Ignatov  * Programs of types that are allowed to be loaded both w/ and w/o (for
2445aac3fc32SAndrey Ignatov  * backward compatibility) expected_attach_type, should have the default attach
2446aac3fc32SAndrey Ignatov  * type assigned to expected_attach_type for the latter case, so that it can be
2447aac3fc32SAndrey Ignatov  * validated later at attach time.
2448aac3fc32SAndrey Ignatov  *
2449aac3fc32SAndrey Ignatov  * bpf_prog_load_fixup_attach_type() sets expected_attach_type in @attr if
2450aac3fc32SAndrey Ignatov  * prog type requires it but has some attach types that have to be backward
2451aac3fc32SAndrey Ignatov  * compatible.
2452aac3fc32SAndrey Ignatov  */
2453aac3fc32SAndrey Ignatov static void bpf_prog_load_fixup_attach_type(union bpf_attr *attr)
2454aac3fc32SAndrey Ignatov {
2455aac3fc32SAndrey Ignatov 	switch (attr->prog_type) {
2456aac3fc32SAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK:
2457aac3fc32SAndrey Ignatov 		/* Unfortunately BPF_ATTACH_TYPE_UNSPEC enumeration doesn't
2458aac3fc32SAndrey Ignatov 		 * exist so checking for non-zero is the way to go here.
2459aac3fc32SAndrey Ignatov 		 */
2460aac3fc32SAndrey Ignatov 		if (!attr->expected_attach_type)
2461aac3fc32SAndrey Ignatov 			attr->expected_attach_type =
2462aac3fc32SAndrey Ignatov 				BPF_CGROUP_INET_SOCK_CREATE;
2463aac3fc32SAndrey Ignatov 		break;
2464d5e4ddaeSKuniyuki Iwashima 	case BPF_PROG_TYPE_SK_REUSEPORT:
2465d5e4ddaeSKuniyuki Iwashima 		if (!attr->expected_attach_type)
2466d5e4ddaeSKuniyuki Iwashima 			attr->expected_attach_type =
2467d5e4ddaeSKuniyuki Iwashima 				BPF_SK_REUSEPORT_SELECT;
2468d5e4ddaeSKuniyuki Iwashima 		break;
2469aac3fc32SAndrey Ignatov 	}
2470aac3fc32SAndrey Ignatov }
2471aac3fc32SAndrey Ignatov 
24725e43f899SAndrey Ignatov static int
2473ccfe29ebSAlexei Starovoitov bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
2474ccfe29ebSAlexei Starovoitov 			   enum bpf_attach_type expected_attach_type,
2475290248a5SAndrii Nakryiko 			   struct btf *attach_btf, u32 btf_id,
2476290248a5SAndrii Nakryiko 			   struct bpf_prog *dst_prog)
24775e43f899SAndrey Ignatov {
247827ae7997SMartin KaFai Lau 	if (btf_id) {
2479c108e3c1SAlexei Starovoitov 		if (btf_id > BTF_MAX_TYPE)
2480c108e3c1SAlexei Starovoitov 			return -EINVAL;
248127ae7997SMartin KaFai Lau 
2482290248a5SAndrii Nakryiko 		if (!attach_btf && !dst_prog)
2483290248a5SAndrii Nakryiko 			return -EINVAL;
2484290248a5SAndrii Nakryiko 
248527ae7997SMartin KaFai Lau 		switch (prog_type) {
248627ae7997SMartin KaFai Lau 		case BPF_PROG_TYPE_TRACING:
24879e4e01dfSKP Singh 		case BPF_PROG_TYPE_LSM:
248827ae7997SMartin KaFai Lau 		case BPF_PROG_TYPE_STRUCT_OPS:
2489be8704ffSAlexei Starovoitov 		case BPF_PROG_TYPE_EXT:
2490c108e3c1SAlexei Starovoitov 			break;
2491c108e3c1SAlexei Starovoitov 		default:
2492c108e3c1SAlexei Starovoitov 			return -EINVAL;
2493c108e3c1SAlexei Starovoitov 		}
249427ae7997SMartin KaFai Lau 	}
249527ae7997SMartin KaFai Lau 
2496290248a5SAndrii Nakryiko 	if (attach_btf && (!btf_id || dst_prog))
2497290248a5SAndrii Nakryiko 		return -EINVAL;
2498290248a5SAndrii Nakryiko 
2499290248a5SAndrii Nakryiko 	if (dst_prog && prog_type != BPF_PROG_TYPE_TRACING &&
2500be8704ffSAlexei Starovoitov 	    prog_type != BPF_PROG_TYPE_EXT)
250127ae7997SMartin KaFai Lau 		return -EINVAL;
2502c108e3c1SAlexei Starovoitov 
2503c108e3c1SAlexei Starovoitov 	switch (prog_type) {
2504aac3fc32SAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK:
2505aac3fc32SAndrey Ignatov 		switch (expected_attach_type) {
2506aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET_SOCK_CREATE:
2507f5836749SStanislav Fomichev 		case BPF_CGROUP_INET_SOCK_RELEASE:
2508aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET4_POST_BIND:
2509aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET6_POST_BIND:
2510aac3fc32SAndrey Ignatov 			return 0;
2511aac3fc32SAndrey Ignatov 		default:
2512aac3fc32SAndrey Ignatov 			return -EINVAL;
2513aac3fc32SAndrey Ignatov 		}
25144fbac77dSAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
25154fbac77dSAndrey Ignatov 		switch (expected_attach_type) {
25164fbac77dSAndrey Ignatov 		case BPF_CGROUP_INET4_BIND:
25174fbac77dSAndrey Ignatov 		case BPF_CGROUP_INET6_BIND:
2518d74bad4eSAndrey Ignatov 		case BPF_CGROUP_INET4_CONNECT:
2519d74bad4eSAndrey Ignatov 		case BPF_CGROUP_INET6_CONNECT:
2520859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_CONNECT:
25211b66d253SDaniel Borkmann 		case BPF_CGROUP_INET4_GETPEERNAME:
25221b66d253SDaniel Borkmann 		case BPF_CGROUP_INET6_GETPEERNAME:
2523859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_GETPEERNAME:
25241b66d253SDaniel Borkmann 		case BPF_CGROUP_INET4_GETSOCKNAME:
25251b66d253SDaniel Borkmann 		case BPF_CGROUP_INET6_GETSOCKNAME:
2526859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_GETSOCKNAME:
25271cedee13SAndrey Ignatov 		case BPF_CGROUP_UDP4_SENDMSG:
25281cedee13SAndrey Ignatov 		case BPF_CGROUP_UDP6_SENDMSG:
2529859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_SENDMSG:
2530983695faSDaniel Borkmann 		case BPF_CGROUP_UDP4_RECVMSG:
2531983695faSDaniel Borkmann 		case BPF_CGROUP_UDP6_RECVMSG:
2532859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_RECVMSG:
25335e43f899SAndrey Ignatov 			return 0;
25344fbac77dSAndrey Ignatov 		default:
25354fbac77dSAndrey Ignatov 			return -EINVAL;
25364fbac77dSAndrey Ignatov 		}
25375cf1e914Sbrakmo 	case BPF_PROG_TYPE_CGROUP_SKB:
25385cf1e914Sbrakmo 		switch (expected_attach_type) {
25395cf1e914Sbrakmo 		case BPF_CGROUP_INET_INGRESS:
25405cf1e914Sbrakmo 		case BPF_CGROUP_INET_EGRESS:
25415cf1e914Sbrakmo 			return 0;
25425cf1e914Sbrakmo 		default:
25435cf1e914Sbrakmo 			return -EINVAL;
25445cf1e914Sbrakmo 		}
25450d01da6aSStanislav Fomichev 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
25460d01da6aSStanislav Fomichev 		switch (expected_attach_type) {
25470d01da6aSStanislav Fomichev 		case BPF_CGROUP_SETSOCKOPT:
25480d01da6aSStanislav Fomichev 		case BPF_CGROUP_GETSOCKOPT:
25490d01da6aSStanislav Fomichev 			return 0;
25500d01da6aSStanislav Fomichev 		default:
25510d01da6aSStanislav Fomichev 			return -EINVAL;
25520d01da6aSStanislav Fomichev 		}
2553e9ddbb77SJakub Sitnicki 	case BPF_PROG_TYPE_SK_LOOKUP:
2554e9ddbb77SJakub Sitnicki 		if (expected_attach_type == BPF_SK_LOOKUP)
2555e9ddbb77SJakub Sitnicki 			return 0;
2556e9ddbb77SJakub Sitnicki 		return -EINVAL;
2557d5e4ddaeSKuniyuki Iwashima 	case BPF_PROG_TYPE_SK_REUSEPORT:
2558d5e4ddaeSKuniyuki Iwashima 		switch (expected_attach_type) {
2559d5e4ddaeSKuniyuki Iwashima 		case BPF_SK_REUSEPORT_SELECT:
2560d5e4ddaeSKuniyuki Iwashima 		case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE:
2561d5e4ddaeSKuniyuki Iwashima 			return 0;
2562d5e4ddaeSKuniyuki Iwashima 		default:
2563d5e4ddaeSKuniyuki Iwashima 			return -EINVAL;
2564d5e4ddaeSKuniyuki Iwashima 		}
2565132328e8SFlorian Westphal 	case BPF_PROG_TYPE_NETFILTER:
2566132328e8SFlorian Westphal 		if (expected_attach_type == BPF_NETFILTER)
2567132328e8SFlorian Westphal 			return 0;
2568132328e8SFlorian Westphal 		return -EINVAL;
256979a7f8bdSAlexei Starovoitov 	case BPF_PROG_TYPE_SYSCALL:
2570be8704ffSAlexei Starovoitov 	case BPF_PROG_TYPE_EXT:
2571be8704ffSAlexei Starovoitov 		if (expected_attach_type)
2572be8704ffSAlexei Starovoitov 			return -EINVAL;
2573df561f66SGustavo A. R. Silva 		fallthrough;
25744fbac77dSAndrey Ignatov 	default:
25754fbac77dSAndrey Ignatov 		return 0;
25764fbac77dSAndrey Ignatov 	}
25775e43f899SAndrey Ignatov }
25785e43f899SAndrey Ignatov 
25792c78ee89SAlexei Starovoitov static bool is_net_admin_prog_type(enum bpf_prog_type prog_type)
25802c78ee89SAlexei Starovoitov {
25812c78ee89SAlexei Starovoitov 	switch (prog_type) {
25822c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SCHED_CLS:
25832c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SCHED_ACT:
25842c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_XDP:
25852c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_IN:
25862c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_OUT:
25872c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_XMIT:
25882c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_SEG6LOCAL:
25892c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_SKB:
25902c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_MSG:
25912c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
25922c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_DEVICE:
25932c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCK:
25942c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
25952c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
25962c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
25972c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SOCK_OPS:
25982c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_EXT: /* extends any prog */
259984601d6eSFlorian Westphal 	case BPF_PROG_TYPE_NETFILTER:
26002c78ee89SAlexei Starovoitov 		return true;
26012c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SKB:
26022c78ee89SAlexei Starovoitov 		/* always unpriv */
26032c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_REUSEPORT:
26042c78ee89SAlexei Starovoitov 		/* equivalent to SOCKET_FILTER. need CAP_BPF only */
26052c78ee89SAlexei Starovoitov 	default:
26062c78ee89SAlexei Starovoitov 		return false;
26072c78ee89SAlexei Starovoitov 	}
26082c78ee89SAlexei Starovoitov }
26092c78ee89SAlexei Starovoitov 
26102c78ee89SAlexei Starovoitov static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
26112c78ee89SAlexei Starovoitov {
26122c78ee89SAlexei Starovoitov 	switch (prog_type) {
26132c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_KPROBE:
26142c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_TRACEPOINT:
26152c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_PERF_EVENT:
26162c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_RAW_TRACEPOINT:
26172c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
26182c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_TRACING:
26192c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LSM:
26202c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_STRUCT_OPS: /* has access to struct sock */
26212c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_EXT: /* extends any prog */
26222c78ee89SAlexei Starovoitov 		return true;
26232c78ee89SAlexei Starovoitov 	default:
26242c78ee89SAlexei Starovoitov 		return false;
26252c78ee89SAlexei Starovoitov 	}
26262c78ee89SAlexei Starovoitov }
26272c78ee89SAlexei Starovoitov 
262809756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
2629caf8f28eSAndrii Nakryiko #define BPF_PROG_LOAD_LAST_FIELD prog_token_fd
263009756af4SAlexei Starovoitov 
263147a71c1fSAndrii Nakryiko static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
263209756af4SAlexei Starovoitov {
263309756af4SAlexei Starovoitov 	enum bpf_prog_type type = attr->prog_type;
2634290248a5SAndrii Nakryiko 	struct bpf_prog *prog, *dst_prog = NULL;
2635290248a5SAndrii Nakryiko 	struct btf *attach_btf = NULL;
2636caf8f28eSAndrii Nakryiko 	struct bpf_token *token = NULL;
2637caf8f28eSAndrii Nakryiko 	bool bpf_cap;
263809756af4SAlexei Starovoitov 	int err;
263909756af4SAlexei Starovoitov 	char license[128];
264009756af4SAlexei Starovoitov 
264109756af4SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_LOAD))
264209756af4SAlexei Starovoitov 		return -EINVAL;
264309756af4SAlexei Starovoitov 
2644c240eff6SJiong Wang 	if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT |
2645c240eff6SJiong Wang 				 BPF_F_ANY_ALIGNMENT |
264610d274e8SAlexei Starovoitov 				 BPF_F_TEST_STATE_FREQ |
26471e6c62a8SAlexei Starovoitov 				 BPF_F_SLEEPABLE |
2648c2f2cdbeSLorenzo Bianconi 				 BPF_F_TEST_RND_HI32 |
26492b3486bcSStanislav Fomichev 				 BPF_F_XDP_HAS_FRAGS |
26505f99f312SAndrii Nakryiko 				 BPF_F_XDP_DEV_BOUND_ONLY |
2651caf8f28eSAndrii Nakryiko 				 BPF_F_TEST_REG_INVARIANTS |
2652caf8f28eSAndrii Nakryiko 				 BPF_F_TOKEN_FD))
2653e07b98d9SDavid S. Miller 		return -EINVAL;
2654e07b98d9SDavid S. Miller 
2655caf8f28eSAndrii Nakryiko 	bpf_prog_load_fixup_attach_type(attr);
2656caf8f28eSAndrii Nakryiko 
2657caf8f28eSAndrii Nakryiko 	if (attr->prog_flags & BPF_F_TOKEN_FD) {
2658caf8f28eSAndrii Nakryiko 		token = bpf_token_get_from_fd(attr->prog_token_fd);
2659caf8f28eSAndrii Nakryiko 		if (IS_ERR(token))
2660caf8f28eSAndrii Nakryiko 			return PTR_ERR(token);
2661caf8f28eSAndrii Nakryiko 		/* if current token doesn't grant prog loading permissions,
2662caf8f28eSAndrii Nakryiko 		 * then we can't use this token, so ignore it and rely on
2663caf8f28eSAndrii Nakryiko 		 * system-wide capabilities checks
2664caf8f28eSAndrii Nakryiko 		 */
2665caf8f28eSAndrii Nakryiko 		if (!bpf_token_allow_cmd(token, BPF_PROG_LOAD) ||
2666caf8f28eSAndrii Nakryiko 		    !bpf_token_allow_prog_type(token, attr->prog_type,
2667caf8f28eSAndrii Nakryiko 					       attr->expected_attach_type)) {
2668caf8f28eSAndrii Nakryiko 			bpf_token_put(token);
2669caf8f28eSAndrii Nakryiko 			token = NULL;
2670caf8f28eSAndrii Nakryiko 		}
2671caf8f28eSAndrii Nakryiko 	}
2672caf8f28eSAndrii Nakryiko 
2673caf8f28eSAndrii Nakryiko 	bpf_cap = bpf_token_capable(token, CAP_BPF);
2674caf8f28eSAndrii Nakryiko 	err = -EPERM;
2675caf8f28eSAndrii Nakryiko 
2676e9ee9efcSDavid Miller 	if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
2677e9ee9efcSDavid Miller 	    (attr->prog_flags & BPF_F_ANY_ALIGNMENT) &&
2678caf8f28eSAndrii Nakryiko 	    !bpf_cap)
2679caf8f28eSAndrii Nakryiko 		goto put_token;
2680e9ee9efcSDavid Miller 
26811d28635aSAndrii Nakryiko 	/* Intent here is for unprivileged_bpf_disabled to block BPF program
26821d28635aSAndrii Nakryiko 	 * creation for unprivileged users; other actions depend
26831d28635aSAndrii Nakryiko 	 * on fd availability and access to bpffs, so are dependent on
26841d28635aSAndrii Nakryiko 	 * object creation success. Even with unprivileged BPF disabled,
26851d28635aSAndrii Nakryiko 	 * capability checks are still carried out for these
26861d28635aSAndrii Nakryiko 	 * and other operations.
26871d28635aSAndrii Nakryiko 	 */
2688caf8f28eSAndrii Nakryiko 	if (sysctl_unprivileged_bpf_disabled && !bpf_cap)
2689caf8f28eSAndrii Nakryiko 		goto put_token;
269009756af4SAlexei Starovoitov 
2691c04c0d2bSAlexei Starovoitov 	if (attr->insn_cnt == 0 ||
2692caf8f28eSAndrii Nakryiko 	    attr->insn_cnt > (bpf_cap ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) {
2693caf8f28eSAndrii Nakryiko 		err = -E2BIG;
2694caf8f28eSAndrii Nakryiko 		goto put_token;
2695caf8f28eSAndrii Nakryiko 	}
269680b7d819SChenbo Feng 	if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
269780b7d819SChenbo Feng 	    type != BPF_PROG_TYPE_CGROUP_SKB &&
2698caf8f28eSAndrii Nakryiko 	    !bpf_cap)
2699caf8f28eSAndrii Nakryiko 		goto put_token;
27002c78ee89SAlexei Starovoitov 
2701caf8f28eSAndrii Nakryiko 	if (is_net_admin_prog_type(type) && !bpf_token_capable(token, CAP_NET_ADMIN))
2702caf8f28eSAndrii Nakryiko 		goto put_token;
2703caf8f28eSAndrii Nakryiko 	if (is_perfmon_prog_type(type) && !bpf_token_capable(token, CAP_PERFMON))
2704caf8f28eSAndrii Nakryiko 		goto put_token;
27051be7f75dSAlexei Starovoitov 
2706290248a5SAndrii Nakryiko 	/* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog
2707290248a5SAndrii Nakryiko 	 * or btf, we need to check which one it is
2708290248a5SAndrii Nakryiko 	 */
2709290248a5SAndrii Nakryiko 	if (attr->attach_prog_fd) {
2710290248a5SAndrii Nakryiko 		dst_prog = bpf_prog_get(attr->attach_prog_fd);
2711290248a5SAndrii Nakryiko 		if (IS_ERR(dst_prog)) {
2712290248a5SAndrii Nakryiko 			dst_prog = NULL;
2713290248a5SAndrii Nakryiko 			attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd);
2714caf8f28eSAndrii Nakryiko 			if (IS_ERR(attach_btf)) {
2715caf8f28eSAndrii Nakryiko 				err = -EINVAL;
2716caf8f28eSAndrii Nakryiko 				goto put_token;
2717caf8f28eSAndrii Nakryiko 			}
2718290248a5SAndrii Nakryiko 			if (!btf_is_kernel(attach_btf)) {
27198bdd8e27SAndrii Nakryiko 				/* attaching through specifying bpf_prog's BTF
27208bdd8e27SAndrii Nakryiko 				 * objects directly might be supported eventually
27218bdd8e27SAndrii Nakryiko 				 */
2722290248a5SAndrii Nakryiko 				btf_put(attach_btf);
2723caf8f28eSAndrii Nakryiko 				err = -ENOTSUPP;
2724caf8f28eSAndrii Nakryiko 				goto put_token;
2725290248a5SAndrii Nakryiko 			}
2726290248a5SAndrii Nakryiko 		}
2727290248a5SAndrii Nakryiko 	} else if (attr->attach_btf_id) {
2728290248a5SAndrii Nakryiko 		/* fall back to vmlinux BTF, if BTF type ID is specified */
2729290248a5SAndrii Nakryiko 		attach_btf = bpf_get_btf_vmlinux();
2730caf8f28eSAndrii Nakryiko 		if (IS_ERR(attach_btf)) {
2731caf8f28eSAndrii Nakryiko 			err = PTR_ERR(attach_btf);
2732caf8f28eSAndrii Nakryiko 			goto put_token;
2733caf8f28eSAndrii Nakryiko 		}
2734caf8f28eSAndrii Nakryiko 		if (!attach_btf) {
2735caf8f28eSAndrii Nakryiko 			err = -EINVAL;
2736caf8f28eSAndrii Nakryiko 			goto put_token;
2737caf8f28eSAndrii Nakryiko 		}
2738290248a5SAndrii Nakryiko 		btf_get(attach_btf);
2739290248a5SAndrii Nakryiko 	}
2740290248a5SAndrii Nakryiko 
2741ccfe29ebSAlexei Starovoitov 	if (bpf_prog_load_check_attach(type, attr->expected_attach_type,
2742290248a5SAndrii Nakryiko 				       attach_btf, attr->attach_btf_id,
2743290248a5SAndrii Nakryiko 				       dst_prog)) {
2744290248a5SAndrii Nakryiko 		if (dst_prog)
2745290248a5SAndrii Nakryiko 			bpf_prog_put(dst_prog);
2746290248a5SAndrii Nakryiko 		if (attach_btf)
2747290248a5SAndrii Nakryiko 			btf_put(attach_btf);
2748caf8f28eSAndrii Nakryiko 		err = -EINVAL;
2749caf8f28eSAndrii Nakryiko 		goto put_token;
2750290248a5SAndrii Nakryiko 	}
27515e43f899SAndrey Ignatov 
275209756af4SAlexei Starovoitov 	/* plain bpf_prog allocation */
275309756af4SAlexei Starovoitov 	prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
2754290248a5SAndrii Nakryiko 	if (!prog) {
2755290248a5SAndrii Nakryiko 		if (dst_prog)
2756290248a5SAndrii Nakryiko 			bpf_prog_put(dst_prog);
2757290248a5SAndrii Nakryiko 		if (attach_btf)
2758290248a5SAndrii Nakryiko 			btf_put(attach_btf);
2759caf8f28eSAndrii Nakryiko 		err = -EINVAL;
2760caf8f28eSAndrii Nakryiko 		goto put_token;
2761290248a5SAndrii Nakryiko 	}
276209756af4SAlexei Starovoitov 
27635e43f899SAndrey Ignatov 	prog->expected_attach_type = attr->expected_attach_type;
2764290248a5SAndrii Nakryiko 	prog->aux->attach_btf = attach_btf;
2765ccfe29ebSAlexei Starovoitov 	prog->aux->attach_btf_id = attr->attach_btf_id;
27663aac1eadSToke Høiland-Jørgensen 	prog->aux->dst_prog = dst_prog;
27672b3486bcSStanislav Fomichev 	prog->aux->dev_bound = !!attr->prog_ifindex;
27681e6c62a8SAlexei Starovoitov 	prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE;
2769c2f2cdbeSLorenzo Bianconi 	prog->aux->xdp_has_frags = attr->prog_flags & BPF_F_XDP_HAS_FRAGS;
27709a18eedbSJakub Kicinski 
2771caf8f28eSAndrii Nakryiko 	/* move token into prog->aux, reuse taken refcnt */
2772caf8f28eSAndrii Nakryiko 	prog->aux->token = token;
2773caf8f28eSAndrii Nakryiko 	token = NULL;
2774caf8f28eSAndrii Nakryiko 
2775d17aff80SAndrii Nakryiko 	err = security_bpf_prog_alloc(prog->aux);
2776d17aff80SAndrii Nakryiko 	if (err)
2777d17aff80SAndrii Nakryiko 		goto free_prog;
2778e1cef620SAndrii Nakryiko 
27793ac1f01bSRoman Gushchin 	prog->aux->user = get_current_user();
278009756af4SAlexei Starovoitov 	prog->len = attr->insn_cnt;
278109756af4SAlexei Starovoitov 
278209756af4SAlexei Starovoitov 	err = -EFAULT;
2783af2ac3e1SAlexei Starovoitov 	if (copy_from_bpfptr(prog->insns,
2784af2ac3e1SAlexei Starovoitov 			     make_bpfptr(attr->insns, uattr.is_kernel),
2785aafe6ae9SDaniel Borkmann 			     bpf_prog_insn_size(prog)) != 0)
2786d17aff80SAndrii Nakryiko 		goto free_prog_sec;
27877f6719f7SAndrii Nakryiko 	/* copy eBPF program license from user space */
27887f6719f7SAndrii Nakryiko 	if (strncpy_from_bpfptr(license,
27897f6719f7SAndrii Nakryiko 				make_bpfptr(attr->license, uattr.is_kernel),
27907f6719f7SAndrii Nakryiko 				sizeof(license) - 1) < 0)
2791d17aff80SAndrii Nakryiko 		goto free_prog_sec;
27927f6719f7SAndrii Nakryiko 	license[sizeof(license) - 1] = 0;
27937f6719f7SAndrii Nakryiko 
27947f6719f7SAndrii Nakryiko 	/* eBPF programs must be GPL compatible to use GPL-ed functions */
27957f6719f7SAndrii Nakryiko 	prog->gpl_compatible = license_is_gpl_compatible(license) ? 1 : 0;
279609756af4SAlexei Starovoitov 
279709756af4SAlexei Starovoitov 	prog->orig_prog = NULL;
2798a91263d5SDaniel Borkmann 	prog->jited = 0;
279909756af4SAlexei Starovoitov 
280085192dbfSAndrii Nakryiko 	atomic64_set(&prog->aux->refcnt, 1);
280109756af4SAlexei Starovoitov 
28029a18eedbSJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux)) {
28032b3486bcSStanislav Fomichev 		err = bpf_prog_dev_bound_init(prog, attr);
2804ab3f0063SJakub Kicinski 		if (err)
2805d17aff80SAndrii Nakryiko 			goto free_prog_sec;
2806ab3f0063SJakub Kicinski 	}
2807ab3f0063SJakub Kicinski 
2808fd7c211dSToke Høiland-Jørgensen 	if (type == BPF_PROG_TYPE_EXT && dst_prog &&
2809fd7c211dSToke Høiland-Jørgensen 	    bpf_prog_is_dev_bound(dst_prog->aux)) {
2810fd7c211dSToke Høiland-Jørgensen 		err = bpf_prog_dev_bound_inherit(prog, dst_prog);
2811cb4d2b3fSMartin KaFai Lau 		if (err)
2812d17aff80SAndrii Nakryiko 			goto free_prog_sec;
2813cb4d2b3fSMartin KaFai Lau 	}
2814cb4d2b3fSMartin KaFai Lau 
281519bfcdf9SDmitrii Dolgov 	/*
281619bfcdf9SDmitrii Dolgov 	 * Bookkeeping for managing the program attachment chain.
281719bfcdf9SDmitrii Dolgov 	 *
281819bfcdf9SDmitrii Dolgov 	 * It might be tempting to set attach_tracing_prog flag at the attachment
281919bfcdf9SDmitrii Dolgov 	 * time, but this will not prevent from loading bunch of tracing prog
282019bfcdf9SDmitrii Dolgov 	 * first, then attach them one to another.
282119bfcdf9SDmitrii Dolgov 	 *
282219bfcdf9SDmitrii Dolgov 	 * The flag attach_tracing_prog is set for the whole program lifecycle, and
282319bfcdf9SDmitrii Dolgov 	 * doesn't have to be cleared in bpf_tracing_link_release, since tracing
282419bfcdf9SDmitrii Dolgov 	 * programs cannot change attachment target.
282519bfcdf9SDmitrii Dolgov 	 */
282619bfcdf9SDmitrii Dolgov 	if (type == BPF_PROG_TYPE_TRACING && dst_prog &&
282719bfcdf9SDmitrii Dolgov 	    dst_prog->type == BPF_PROG_TYPE_TRACING) {
282819bfcdf9SDmitrii Dolgov 		prog->aux->attach_tracing_prog = true;
282919bfcdf9SDmitrii Dolgov 	}
283019bfcdf9SDmitrii Dolgov 
283109756af4SAlexei Starovoitov 	/* find program type: socket_filter vs tracing_filter */
283209756af4SAlexei Starovoitov 	err = find_prog_type(type, prog);
283309756af4SAlexei Starovoitov 	if (err < 0)
2834d17aff80SAndrii Nakryiko 		goto free_prog_sec;
283509756af4SAlexei Starovoitov 
28369285ec4cSJason A. Donenfeld 	prog->aux->load_time = ktime_get_boottime_ns();
28378e7ae251SMartin KaFai Lau 	err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name,
28388e7ae251SMartin KaFai Lau 			       sizeof(attr->prog_name));
28398e7ae251SMartin KaFai Lau 	if (err < 0)
28403ac1f01bSRoman Gushchin 		goto free_prog_sec;
2841cb4d2b3fSMartin KaFai Lau 
284209756af4SAlexei Starovoitov 	/* run eBPF verifier */
284347a71c1fSAndrii Nakryiko 	err = bpf_check(&prog, attr, uattr, uattr_size);
284409756af4SAlexei Starovoitov 	if (err < 0)
284509756af4SAlexei Starovoitov 		goto free_used_maps;
284609756af4SAlexei Starovoitov 
2847d1c55ab5SDaniel Borkmann 	prog = bpf_prog_select_runtime(prog, &err);
284804fd61abSAlexei Starovoitov 	if (err < 0)
284904fd61abSAlexei Starovoitov 		goto free_used_maps;
285009756af4SAlexei Starovoitov 
2851dc4bb0e2SMartin KaFai Lau 	err = bpf_prog_alloc_id(prog);
2852dc4bb0e2SMartin KaFai Lau 	if (err)
2853dc4bb0e2SMartin KaFai Lau 		goto free_used_maps;
2854dc4bb0e2SMartin KaFai Lau 
2855c751798aSDaniel Borkmann 	/* Upon success of bpf_prog_alloc_id(), the BPF prog is
2856c751798aSDaniel Borkmann 	 * effectively publicly exposed. However, retrieving via
2857c751798aSDaniel Borkmann 	 * bpf_prog_get_fd_by_id() will take another reference,
2858c751798aSDaniel Borkmann 	 * therefore it cannot be gone underneath us.
2859c751798aSDaniel Borkmann 	 *
2860c751798aSDaniel Borkmann 	 * Only for the time /after/ successful bpf_prog_new_fd()
2861c751798aSDaniel Borkmann 	 * and before returning to userspace, we might just hold
2862c751798aSDaniel Borkmann 	 * one reference and any parallel close on that fd could
2863c751798aSDaniel Borkmann 	 * rip everything out. Hence, below notifications must
2864c751798aSDaniel Borkmann 	 * happen before bpf_prog_new_fd().
2865c751798aSDaniel Borkmann 	 *
2866c751798aSDaniel Borkmann 	 * Also, any failure handling from this point onwards must
2867c751798aSDaniel Borkmann 	 * be using bpf_prog_put() given the program is exposed.
2868b16d9aa4SMartin KaFai Lau 	 */
286974451e66SDaniel Borkmann 	bpf_prog_kallsyms_add(prog);
28706ee52e2aSSong Liu 	perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0);
2871bae141f5SDaniel Borkmann 	bpf_audit_prog(prog, BPF_AUDIT_LOAD);
2872c751798aSDaniel Borkmann 
2873c751798aSDaniel Borkmann 	err = bpf_prog_new_fd(prog);
2874c751798aSDaniel Borkmann 	if (err < 0)
2875c751798aSDaniel Borkmann 		bpf_prog_put(prog);
287609756af4SAlexei Starovoitov 	return err;
287709756af4SAlexei Starovoitov 
287809756af4SAlexei Starovoitov free_used_maps:
2879cd7455f1SDaniel Borkmann 	/* In case we have subprogs, we need to wait for a grace
2880cd7455f1SDaniel Borkmann 	 * period before we can tear down JIT memory since symbols
2881cd7455f1SDaniel Borkmann 	 * are already exposed under kallsyms.
2882cd7455f1SDaniel Borkmann 	 */
2883335d1c5bSKumar Kartikeya Dwivedi 	__bpf_prog_put_noref(prog, prog->aux->real_func_cnt);
2884cd7455f1SDaniel Borkmann 	return err;
2885afdb09c7SChenbo Feng free_prog_sec:
2886c3dd6e94SAndrii Nakryiko 	free_uid(prog->aux->user);
2887d17aff80SAndrii Nakryiko 	security_bpf_prog_free(prog->aux);
2888d17aff80SAndrii Nakryiko free_prog:
288922dc4a0fSAndrii Nakryiko 	if (prog->aux->attach_btf)
289022dc4a0fSAndrii Nakryiko 		btf_put(prog->aux->attach_btf);
289109756af4SAlexei Starovoitov 	bpf_prog_free(prog);
2892caf8f28eSAndrii Nakryiko put_token:
2893caf8f28eSAndrii Nakryiko 	bpf_token_put(token);
289409756af4SAlexei Starovoitov 	return err;
289509756af4SAlexei Starovoitov }
289609756af4SAlexei Starovoitov 
2897cb8edce2SAndrii Nakryiko #define BPF_OBJ_LAST_FIELD path_fd
2898b2197755SDaniel Borkmann 
2899b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr)
2900b2197755SDaniel Borkmann {
2901cb8edce2SAndrii Nakryiko 	int path_fd;
2902cb8edce2SAndrii Nakryiko 
2903cb8edce2SAndrii Nakryiko 	if (CHECK_ATTR(BPF_OBJ) || attr->file_flags & ~BPF_F_PATH_FD)
2904b2197755SDaniel Borkmann 		return -EINVAL;
2905b2197755SDaniel Borkmann 
2906cb8edce2SAndrii Nakryiko 	/* path_fd has to be accompanied by BPF_F_PATH_FD flag */
2907cb8edce2SAndrii Nakryiko 	if (!(attr->file_flags & BPF_F_PATH_FD) && attr->path_fd)
2908cb8edce2SAndrii Nakryiko 		return -EINVAL;
2909cb8edce2SAndrii Nakryiko 
2910cb8edce2SAndrii Nakryiko 	path_fd = attr->file_flags & BPF_F_PATH_FD ? attr->path_fd : AT_FDCWD;
2911cb8edce2SAndrii Nakryiko 	return bpf_obj_pin_user(attr->bpf_fd, path_fd,
2912cb8edce2SAndrii Nakryiko 				u64_to_user_ptr(attr->pathname));
2913b2197755SDaniel Borkmann }
2914b2197755SDaniel Borkmann 
2915b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr)
2916b2197755SDaniel Borkmann {
2917cb8edce2SAndrii Nakryiko 	int path_fd;
2918cb8edce2SAndrii Nakryiko 
29196e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 ||
2920cb8edce2SAndrii Nakryiko 	    attr->file_flags & ~(BPF_OBJ_FLAG_MASK | BPF_F_PATH_FD))
2921b2197755SDaniel Borkmann 		return -EINVAL;
2922b2197755SDaniel Borkmann 
2923cb8edce2SAndrii Nakryiko 	/* path_fd has to be accompanied by BPF_F_PATH_FD flag */
2924cb8edce2SAndrii Nakryiko 	if (!(attr->file_flags & BPF_F_PATH_FD) && attr->path_fd)
2925cb8edce2SAndrii Nakryiko 		return -EINVAL;
2926cb8edce2SAndrii Nakryiko 
2927cb8edce2SAndrii Nakryiko 	path_fd = attr->file_flags & BPF_F_PATH_FD ? attr->path_fd : AT_FDCWD;
2928cb8edce2SAndrii Nakryiko 	return bpf_obj_get_user(path_fd, u64_to_user_ptr(attr->pathname),
29296e71b04aSChenbo Feng 				attr->file_flags);
2930b2197755SDaniel Borkmann }
2931b2197755SDaniel Borkmann 
2932f2e10bffSAndrii Nakryiko void bpf_link_init(struct bpf_link *link, enum bpf_link_type type,
2933a3b80e10SAndrii Nakryiko 		   const struct bpf_link_ops *ops, struct bpf_prog *prog)
293470ed506cSAndrii Nakryiko {
293570ed506cSAndrii Nakryiko 	atomic64_set(&link->refcnt, 1);
2936f2e10bffSAndrii Nakryiko 	link->type = type;
2937a3b80e10SAndrii Nakryiko 	link->id = 0;
293870ed506cSAndrii Nakryiko 	link->ops = ops;
293970ed506cSAndrii Nakryiko 	link->prog = prog;
294070ed506cSAndrii Nakryiko }
294170ed506cSAndrii Nakryiko 
2942a3b80e10SAndrii Nakryiko static void bpf_link_free_id(int id)
2943a3b80e10SAndrii Nakryiko {
2944a3b80e10SAndrii Nakryiko 	if (!id)
2945a3b80e10SAndrii Nakryiko 		return;
2946a3b80e10SAndrii Nakryiko 
2947a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
2948a3b80e10SAndrii Nakryiko 	idr_remove(&link_idr, id);
2949a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
2950a3b80e10SAndrii Nakryiko }
2951a3b80e10SAndrii Nakryiko 
295298868668SAndrii Nakryiko /* Clean up bpf_link and corresponding anon_inode file and FD. After
295398868668SAndrii Nakryiko  * anon_inode is created, bpf_link can't be just kfree()'d due to deferred
2954a3b80e10SAndrii Nakryiko  * anon_inode's release() call. This helper marks bpf_link as
2955a3b80e10SAndrii Nakryiko  * defunct, releases anon_inode file and puts reserved FD. bpf_prog's refcnt
2956a3b80e10SAndrii Nakryiko  * is not decremented, it's the responsibility of a calling code that failed
2957a3b80e10SAndrii Nakryiko  * to complete bpf_link initialization.
295889ae89f5SJiri Olsa  * This helper eventually calls link's dealloc callback, but does not call
295989ae89f5SJiri Olsa  * link's release callback.
296098868668SAndrii Nakryiko  */
2961a3b80e10SAndrii Nakryiko void bpf_link_cleanup(struct bpf_link_primer *primer)
2962babf3164SAndrii Nakryiko {
2963a3b80e10SAndrii Nakryiko 	primer->link->prog = NULL;
2964a3b80e10SAndrii Nakryiko 	bpf_link_free_id(primer->id);
2965a3b80e10SAndrii Nakryiko 	fput(primer->file);
2966a3b80e10SAndrii Nakryiko 	put_unused_fd(primer->fd);
2967babf3164SAndrii Nakryiko }
2968babf3164SAndrii Nakryiko 
296970ed506cSAndrii Nakryiko void bpf_link_inc(struct bpf_link *link)
297070ed506cSAndrii Nakryiko {
297170ed506cSAndrii Nakryiko 	atomic64_inc(&link->refcnt);
297270ed506cSAndrii Nakryiko }
297370ed506cSAndrii Nakryiko 
297470ed506cSAndrii Nakryiko /* bpf_link_free is guaranteed to be called from process context */
297570ed506cSAndrii Nakryiko static void bpf_link_free(struct bpf_link *link)
297670ed506cSAndrii Nakryiko {
2977a3b80e10SAndrii Nakryiko 	bpf_link_free_id(link->id);
2978babf3164SAndrii Nakryiko 	if (link->prog) {
2979babf3164SAndrii Nakryiko 		/* detach BPF program, clean up used resources */
298070ed506cSAndrii Nakryiko 		link->ops->release(link);
2981babf3164SAndrii Nakryiko 		bpf_prog_put(link->prog);
2982babf3164SAndrii Nakryiko 	}
2983babf3164SAndrii Nakryiko 	/* free bpf_link and its containing memory */
2984babf3164SAndrii Nakryiko 	link->ops->dealloc(link);
298570ed506cSAndrii Nakryiko }
298670ed506cSAndrii Nakryiko 
298770ed506cSAndrii Nakryiko static void bpf_link_put_deferred(struct work_struct *work)
298870ed506cSAndrii Nakryiko {
298970ed506cSAndrii Nakryiko 	struct bpf_link *link = container_of(work, struct bpf_link, work);
299070ed506cSAndrii Nakryiko 
299170ed506cSAndrii Nakryiko 	bpf_link_free(link);
299270ed506cSAndrii Nakryiko }
299370ed506cSAndrii Nakryiko 
2994ab5d47bdSSebastian Andrzej Siewior /* bpf_link_put might be called from atomic context. It needs to be called
2995ab5d47bdSSebastian Andrzej Siewior  * from sleepable context in order to acquire sleeping locks during the process.
299670ed506cSAndrii Nakryiko  */
299770ed506cSAndrii Nakryiko void bpf_link_put(struct bpf_link *link)
299870ed506cSAndrii Nakryiko {
299970ed506cSAndrii Nakryiko 	if (!atomic64_dec_and_test(&link->refcnt))
300070ed506cSAndrii Nakryiko 		return;
300170ed506cSAndrii Nakryiko 
300270ed506cSAndrii Nakryiko 	INIT_WORK(&link->work, bpf_link_put_deferred);
300370ed506cSAndrii Nakryiko 	schedule_work(&link->work);
300470ed506cSAndrii Nakryiko }
3005cb80ddc6SAlexei Starovoitov EXPORT_SYMBOL(bpf_link_put);
300670ed506cSAndrii Nakryiko 
3007ab5d47bdSSebastian Andrzej Siewior static void bpf_link_put_direct(struct bpf_link *link)
3008ab5d47bdSSebastian Andrzej Siewior {
3009ab5d47bdSSebastian Andrzej Siewior 	if (!atomic64_dec_and_test(&link->refcnt))
3010ab5d47bdSSebastian Andrzej Siewior 		return;
3011ab5d47bdSSebastian Andrzej Siewior 	bpf_link_free(link);
3012ab5d47bdSSebastian Andrzej Siewior }
3013ab5d47bdSSebastian Andrzej Siewior 
301470ed506cSAndrii Nakryiko static int bpf_link_release(struct inode *inode, struct file *filp)
301570ed506cSAndrii Nakryiko {
301670ed506cSAndrii Nakryiko 	struct bpf_link *link = filp->private_data;
301770ed506cSAndrii Nakryiko 
3018ab5d47bdSSebastian Andrzej Siewior 	bpf_link_put_direct(link);
3019fec56f58SAlexei Starovoitov 	return 0;
3020fec56f58SAlexei Starovoitov }
3021fec56f58SAlexei Starovoitov 
302270ed506cSAndrii Nakryiko #ifdef CONFIG_PROC_FS
3023f2e10bffSAndrii Nakryiko #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type)
3024f2e10bffSAndrii Nakryiko #define BPF_MAP_TYPE(_id, _ops)
3025f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name) [_id] = #_name,
3026f2e10bffSAndrii Nakryiko static const char *bpf_link_type_strs[] = {
3027f2e10bffSAndrii Nakryiko 	[BPF_LINK_TYPE_UNSPEC] = "<invalid>",
3028f2e10bffSAndrii Nakryiko #include <linux/bpf_types.h>
3029f2e10bffSAndrii Nakryiko };
3030f2e10bffSAndrii Nakryiko #undef BPF_PROG_TYPE
3031f2e10bffSAndrii Nakryiko #undef BPF_MAP_TYPE
3032f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE
303370ed506cSAndrii Nakryiko 
303470ed506cSAndrii Nakryiko static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
303570ed506cSAndrii Nakryiko {
303670ed506cSAndrii Nakryiko 	const struct bpf_link *link = filp->private_data;
303770ed506cSAndrii Nakryiko 	const struct bpf_prog *prog = link->prog;
303870ed506cSAndrii Nakryiko 	char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
303970ed506cSAndrii Nakryiko 
304070ed506cSAndrii Nakryiko 	seq_printf(m,
304170ed506cSAndrii Nakryiko 		   "link_type:\t%s\n"
304268b04864SKui-Feng Lee 		   "link_id:\t%u\n",
304368b04864SKui-Feng Lee 		   bpf_link_type_strs[link->type],
304468b04864SKui-Feng Lee 		   link->id);
304568b04864SKui-Feng Lee 	if (prog) {
304668b04864SKui-Feng Lee 		bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
304768b04864SKui-Feng Lee 		seq_printf(m,
304870ed506cSAndrii Nakryiko 			   "prog_tag:\t%s\n"
304970ed506cSAndrii Nakryiko 			   "prog_id:\t%u\n",
305070ed506cSAndrii Nakryiko 			   prog_tag,
305170ed506cSAndrii Nakryiko 			   prog->aux->id);
305268b04864SKui-Feng Lee 	}
3053f2e10bffSAndrii Nakryiko 	if (link->ops->show_fdinfo)
3054f2e10bffSAndrii Nakryiko 		link->ops->show_fdinfo(link, m);
305570ed506cSAndrii Nakryiko }
305670ed506cSAndrii Nakryiko #endif
305770ed506cSAndrii Nakryiko 
30586f302bfbSZou Wei static const struct file_operations bpf_link_fops = {
305970ed506cSAndrii Nakryiko #ifdef CONFIG_PROC_FS
306070ed506cSAndrii Nakryiko 	.show_fdinfo	= bpf_link_show_fdinfo,
306170ed506cSAndrii Nakryiko #endif
306270ed506cSAndrii Nakryiko 	.release	= bpf_link_release,
3063fec56f58SAlexei Starovoitov 	.read		= bpf_dummy_read,
3064fec56f58SAlexei Starovoitov 	.write		= bpf_dummy_write,
3065fec56f58SAlexei Starovoitov };
3066fec56f58SAlexei Starovoitov 
3067a3b80e10SAndrii Nakryiko static int bpf_link_alloc_id(struct bpf_link *link)
306870ed506cSAndrii Nakryiko {
3069a3b80e10SAndrii Nakryiko 	int id;
3070a3b80e10SAndrii Nakryiko 
3071a3b80e10SAndrii Nakryiko 	idr_preload(GFP_KERNEL);
3072a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
3073a3b80e10SAndrii Nakryiko 	id = idr_alloc_cyclic(&link_idr, link, 1, INT_MAX, GFP_ATOMIC);
3074a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
3075a3b80e10SAndrii Nakryiko 	idr_preload_end();
3076a3b80e10SAndrii Nakryiko 
3077a3b80e10SAndrii Nakryiko 	return id;
307870ed506cSAndrii Nakryiko }
307970ed506cSAndrii Nakryiko 
3080a3b80e10SAndrii Nakryiko /* Prepare bpf_link to be exposed to user-space by allocating anon_inode file,
3081a3b80e10SAndrii Nakryiko  * reserving unused FD and allocating ID from link_idr. This is to be paired
3082a3b80e10SAndrii Nakryiko  * with bpf_link_settle() to install FD and ID and expose bpf_link to
3083a3b80e10SAndrii Nakryiko  * user-space, if bpf_link is successfully attached. If not, bpf_link and
3084a3b80e10SAndrii Nakryiko  * pre-allocated resources are to be freed with bpf_cleanup() call. All the
3085a3b80e10SAndrii Nakryiko  * transient state is passed around in struct bpf_link_primer.
3086a3b80e10SAndrii Nakryiko  * This is preferred way to create and initialize bpf_link, especially when
3087a3b80e10SAndrii Nakryiko  * there are complicated and expensive operations in between creating bpf_link
3088a3b80e10SAndrii Nakryiko  * itself and attaching it to BPF hook. By using bpf_link_prime() and
3089a3b80e10SAndrii Nakryiko  * bpf_link_settle() kernel code using bpf_link doesn't have to perform
3090a3b80e10SAndrii Nakryiko  * expensive (and potentially failing) roll back operations in a rare case
3091a3b80e10SAndrii Nakryiko  * that file, FD, or ID can't be allocated.
3092babf3164SAndrii Nakryiko  */
3093a3b80e10SAndrii Nakryiko int bpf_link_prime(struct bpf_link *link, struct bpf_link_primer *primer)
3094babf3164SAndrii Nakryiko {
3095babf3164SAndrii Nakryiko 	struct file *file;
3096a3b80e10SAndrii Nakryiko 	int fd, id;
3097babf3164SAndrii Nakryiko 
3098babf3164SAndrii Nakryiko 	fd = get_unused_fd_flags(O_CLOEXEC);
3099babf3164SAndrii Nakryiko 	if (fd < 0)
3100a3b80e10SAndrii Nakryiko 		return fd;
3101babf3164SAndrii Nakryiko 
3102babf3164SAndrii Nakryiko 
3103a3b80e10SAndrii Nakryiko 	id = bpf_link_alloc_id(link);
3104a3b80e10SAndrii Nakryiko 	if (id < 0) {
3105a3b80e10SAndrii Nakryiko 		put_unused_fd(fd);
3106a3b80e10SAndrii Nakryiko 		return id;
3107a3b80e10SAndrii Nakryiko 	}
3108babf3164SAndrii Nakryiko 
3109babf3164SAndrii Nakryiko 	file = anon_inode_getfile("bpf_link", &bpf_link_fops, link, O_CLOEXEC);
3110babf3164SAndrii Nakryiko 	if (IS_ERR(file)) {
3111138c6767SAndrii Nakryiko 		bpf_link_free_id(id);
3112babf3164SAndrii Nakryiko 		put_unused_fd(fd);
3113138c6767SAndrii Nakryiko 		return PTR_ERR(file);
3114babf3164SAndrii Nakryiko 	}
3115babf3164SAndrii Nakryiko 
3116a3b80e10SAndrii Nakryiko 	primer->link = link;
3117a3b80e10SAndrii Nakryiko 	primer->file = file;
3118a3b80e10SAndrii Nakryiko 	primer->fd = fd;
3119a3b80e10SAndrii Nakryiko 	primer->id = id;
3120a3b80e10SAndrii Nakryiko 	return 0;
3121a3b80e10SAndrii Nakryiko }
3122a3b80e10SAndrii Nakryiko 
3123a3b80e10SAndrii Nakryiko int bpf_link_settle(struct bpf_link_primer *primer)
3124a3b80e10SAndrii Nakryiko {
3125a3b80e10SAndrii Nakryiko 	/* make bpf_link fetchable by ID */
3126a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
3127a3b80e10SAndrii Nakryiko 	primer->link->id = primer->id;
3128a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
3129a3b80e10SAndrii Nakryiko 	/* make bpf_link fetchable by FD */
3130a3b80e10SAndrii Nakryiko 	fd_install(primer->fd, primer->file);
3131a3b80e10SAndrii Nakryiko 	/* pass through installed FD */
3132a3b80e10SAndrii Nakryiko 	return primer->fd;
3133a3b80e10SAndrii Nakryiko }
3134a3b80e10SAndrii Nakryiko 
3135a3b80e10SAndrii Nakryiko int bpf_link_new_fd(struct bpf_link *link)
3136a3b80e10SAndrii Nakryiko {
3137a3b80e10SAndrii Nakryiko 	return anon_inode_getfd("bpf-link", &bpf_link_fops, link, O_CLOEXEC);
3138babf3164SAndrii Nakryiko }
3139babf3164SAndrii Nakryiko 
314070ed506cSAndrii Nakryiko struct bpf_link *bpf_link_get_from_fd(u32 ufd)
314170ed506cSAndrii Nakryiko {
314270ed506cSAndrii Nakryiko 	struct fd f = fdget(ufd);
314370ed506cSAndrii Nakryiko 	struct bpf_link *link;
314470ed506cSAndrii Nakryiko 
314570ed506cSAndrii Nakryiko 	if (!f.file)
314670ed506cSAndrii Nakryiko 		return ERR_PTR(-EBADF);
314770ed506cSAndrii Nakryiko 	if (f.file->f_op != &bpf_link_fops) {
314870ed506cSAndrii Nakryiko 		fdput(f);
314970ed506cSAndrii Nakryiko 		return ERR_PTR(-EINVAL);
315070ed506cSAndrii Nakryiko 	}
315170ed506cSAndrii Nakryiko 
315270ed506cSAndrii Nakryiko 	link = f.file->private_data;
315370ed506cSAndrii Nakryiko 	bpf_link_inc(link);
315470ed506cSAndrii Nakryiko 	fdput(f);
315570ed506cSAndrii Nakryiko 
315670ed506cSAndrii Nakryiko 	return link;
315770ed506cSAndrii Nakryiko }
3158cb80ddc6SAlexei Starovoitov EXPORT_SYMBOL(bpf_link_get_from_fd);
315970ed506cSAndrii Nakryiko 
316070ed506cSAndrii Nakryiko static void bpf_tracing_link_release(struct bpf_link *link)
316170ed506cSAndrii Nakryiko {
31623aac1eadSToke Høiland-Jørgensen 	struct bpf_tracing_link *tr_link =
3163f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
31643aac1eadSToke Høiland-Jørgensen 
3165f7e0beafSKui-Feng Lee 	WARN_ON_ONCE(bpf_trampoline_unlink_prog(&tr_link->link,
31663aac1eadSToke Høiland-Jørgensen 						tr_link->trampoline));
31673aac1eadSToke Høiland-Jørgensen 
31683aac1eadSToke Høiland-Jørgensen 	bpf_trampoline_put(tr_link->trampoline);
31693aac1eadSToke Høiland-Jørgensen 
31703aac1eadSToke Høiland-Jørgensen 	/* tgt_prog is NULL if target is a kernel function */
31713aac1eadSToke Høiland-Jørgensen 	if (tr_link->tgt_prog)
31723aac1eadSToke Høiland-Jørgensen 		bpf_prog_put(tr_link->tgt_prog);
3173babf3164SAndrii Nakryiko }
3174babf3164SAndrii Nakryiko 
3175babf3164SAndrii Nakryiko static void bpf_tracing_link_dealloc(struct bpf_link *link)
3176babf3164SAndrii Nakryiko {
317770ed506cSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
3178f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
317970ed506cSAndrii Nakryiko 
318070ed506cSAndrii Nakryiko 	kfree(tr_link);
318170ed506cSAndrii Nakryiko }
318270ed506cSAndrii Nakryiko 
3183f2e10bffSAndrii Nakryiko static void bpf_tracing_link_show_fdinfo(const struct bpf_link *link,
3184f2e10bffSAndrii Nakryiko 					 struct seq_file *seq)
3185f2e10bffSAndrii Nakryiko {
3186f2e10bffSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
3187f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
3188e859e429SYafang Shao 	u32 target_btf_id, target_obj_id;
3189f2e10bffSAndrii Nakryiko 
3190e859e429SYafang Shao 	bpf_trampoline_unpack_key(tr_link->trampoline->key,
3191e859e429SYafang Shao 				  &target_obj_id, &target_btf_id);
3192f2e10bffSAndrii Nakryiko 	seq_printf(seq,
3193e859e429SYafang Shao 		   "attach_type:\t%d\n"
3194e859e429SYafang Shao 		   "target_obj_id:\t%u\n"
3195e859e429SYafang Shao 		   "target_btf_id:\t%u\n",
3196e859e429SYafang Shao 		   tr_link->attach_type,
3197e859e429SYafang Shao 		   target_obj_id,
3198e859e429SYafang Shao 		   target_btf_id);
3199f2e10bffSAndrii Nakryiko }
3200f2e10bffSAndrii Nakryiko 
3201f2e10bffSAndrii Nakryiko static int bpf_tracing_link_fill_link_info(const struct bpf_link *link,
3202f2e10bffSAndrii Nakryiko 					   struct bpf_link_info *info)
3203f2e10bffSAndrii Nakryiko {
3204f2e10bffSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
3205f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
3206f2e10bffSAndrii Nakryiko 
3207f2e10bffSAndrii Nakryiko 	info->tracing.attach_type = tr_link->attach_type;
3208441e8c66SToke Høiland-Jørgensen 	bpf_trampoline_unpack_key(tr_link->trampoline->key,
3209441e8c66SToke Høiland-Jørgensen 				  &info->tracing.target_obj_id,
3210441e8c66SToke Høiland-Jørgensen 				  &info->tracing.target_btf_id);
3211f2e10bffSAndrii Nakryiko 
3212f2e10bffSAndrii Nakryiko 	return 0;
3213f2e10bffSAndrii Nakryiko }
3214f2e10bffSAndrii Nakryiko 
321570ed506cSAndrii Nakryiko static const struct bpf_link_ops bpf_tracing_link_lops = {
321670ed506cSAndrii Nakryiko 	.release = bpf_tracing_link_release,
3217babf3164SAndrii Nakryiko 	.dealloc = bpf_tracing_link_dealloc,
3218f2e10bffSAndrii Nakryiko 	.show_fdinfo = bpf_tracing_link_show_fdinfo,
3219f2e10bffSAndrii Nakryiko 	.fill_link_info = bpf_tracing_link_fill_link_info,
322070ed506cSAndrii Nakryiko };
322170ed506cSAndrii Nakryiko 
32224a1e7c0cSToke Høiland-Jørgensen static int bpf_tracing_prog_attach(struct bpf_prog *prog,
32234a1e7c0cSToke Høiland-Jørgensen 				   int tgt_prog_fd,
32242fcc8241SKui-Feng Lee 				   u32 btf_id,
32252fcc8241SKui-Feng Lee 				   u64 bpf_cookie)
3226fec56f58SAlexei Starovoitov {
3227a3b80e10SAndrii Nakryiko 	struct bpf_link_primer link_primer;
32283aac1eadSToke Høiland-Jørgensen 	struct bpf_prog *tgt_prog = NULL;
32294a1e7c0cSToke Høiland-Jørgensen 	struct bpf_trampoline *tr = NULL;
323070ed506cSAndrii Nakryiko 	struct bpf_tracing_link *link;
32314a1e7c0cSToke Høiland-Jørgensen 	u64 key = 0;
3232a3b80e10SAndrii Nakryiko 	int err;
3233fec56f58SAlexei Starovoitov 
32349e4e01dfSKP Singh 	switch (prog->type) {
32359e4e01dfSKP Singh 	case BPF_PROG_TYPE_TRACING:
3236fec56f58SAlexei Starovoitov 		if (prog->expected_attach_type != BPF_TRACE_FENTRY &&
3237be8704ffSAlexei Starovoitov 		    prog->expected_attach_type != BPF_TRACE_FEXIT &&
32389e4e01dfSKP Singh 		    prog->expected_attach_type != BPF_MODIFY_RETURN) {
32399e4e01dfSKP Singh 			err = -EINVAL;
32409e4e01dfSKP Singh 			goto out_put_prog;
32419e4e01dfSKP Singh 		}
32429e4e01dfSKP Singh 		break;
32439e4e01dfSKP Singh 	case BPF_PROG_TYPE_EXT:
32449e4e01dfSKP Singh 		if (prog->expected_attach_type != 0) {
32459e4e01dfSKP Singh 			err = -EINVAL;
32469e4e01dfSKP Singh 			goto out_put_prog;
32479e4e01dfSKP Singh 		}
32489e4e01dfSKP Singh 		break;
32499e4e01dfSKP Singh 	case BPF_PROG_TYPE_LSM:
32509e4e01dfSKP Singh 		if (prog->expected_attach_type != BPF_LSM_MAC) {
32519e4e01dfSKP Singh 			err = -EINVAL;
32529e4e01dfSKP Singh 			goto out_put_prog;
32539e4e01dfSKP Singh 		}
32549e4e01dfSKP Singh 		break;
32559e4e01dfSKP Singh 	default:
3256fec56f58SAlexei Starovoitov 		err = -EINVAL;
3257fec56f58SAlexei Starovoitov 		goto out_put_prog;
3258fec56f58SAlexei Starovoitov 	}
3259fec56f58SAlexei Starovoitov 
32604a1e7c0cSToke Høiland-Jørgensen 	if (!!tgt_prog_fd != !!btf_id) {
32614a1e7c0cSToke Høiland-Jørgensen 		err = -EINVAL;
32624a1e7c0cSToke Høiland-Jørgensen 		goto out_put_prog;
32634a1e7c0cSToke Høiland-Jørgensen 	}
32644a1e7c0cSToke Høiland-Jørgensen 
32654a1e7c0cSToke Høiland-Jørgensen 	if (tgt_prog_fd) {
326619bfcdf9SDmitrii Dolgov 		/*
326719bfcdf9SDmitrii Dolgov 		 * For now we only allow new targets for BPF_PROG_TYPE_EXT. If this
326819bfcdf9SDmitrii Dolgov 		 * part would be changed to implement the same for
326919bfcdf9SDmitrii Dolgov 		 * BPF_PROG_TYPE_TRACING, do not forget to update the way how
327019bfcdf9SDmitrii Dolgov 		 * attach_tracing_prog flag is set.
327119bfcdf9SDmitrii Dolgov 		 */
32724a1e7c0cSToke Høiland-Jørgensen 		if (prog->type != BPF_PROG_TYPE_EXT) {
32734a1e7c0cSToke Høiland-Jørgensen 			err = -EINVAL;
32744a1e7c0cSToke Høiland-Jørgensen 			goto out_put_prog;
32754a1e7c0cSToke Høiland-Jørgensen 		}
32764a1e7c0cSToke Høiland-Jørgensen 
32774a1e7c0cSToke Høiland-Jørgensen 		tgt_prog = bpf_prog_get(tgt_prog_fd);
32784a1e7c0cSToke Høiland-Jørgensen 		if (IS_ERR(tgt_prog)) {
32794a1e7c0cSToke Høiland-Jørgensen 			err = PTR_ERR(tgt_prog);
32804a1e7c0cSToke Høiland-Jørgensen 			tgt_prog = NULL;
32814a1e7c0cSToke Høiland-Jørgensen 			goto out_put_prog;
32824a1e7c0cSToke Høiland-Jørgensen 		}
32834a1e7c0cSToke Høiland-Jørgensen 
328422dc4a0fSAndrii Nakryiko 		key = bpf_trampoline_compute_key(tgt_prog, NULL, btf_id);
32854a1e7c0cSToke Høiland-Jørgensen 	}
32864a1e7c0cSToke Høiland-Jørgensen 
328770ed506cSAndrii Nakryiko 	link = kzalloc(sizeof(*link), GFP_USER);
328870ed506cSAndrii Nakryiko 	if (!link) {
328970ed506cSAndrii Nakryiko 		err = -ENOMEM;
3290fec56f58SAlexei Starovoitov 		goto out_put_prog;
3291fec56f58SAlexei Starovoitov 	}
3292f7e0beafSKui-Feng Lee 	bpf_link_init(&link->link.link, BPF_LINK_TYPE_TRACING,
3293f2e10bffSAndrii Nakryiko 		      &bpf_tracing_link_lops, prog);
3294f2e10bffSAndrii Nakryiko 	link->attach_type = prog->expected_attach_type;
32952fcc8241SKui-Feng Lee 	link->link.cookie = bpf_cookie;
3296fec56f58SAlexei Starovoitov 
32973aac1eadSToke Høiland-Jørgensen 	mutex_lock(&prog->aux->dst_mutex);
3298babf3164SAndrii Nakryiko 
32994a1e7c0cSToke Høiland-Jørgensen 	/* There are a few possible cases here:
33004a1e7c0cSToke Høiland-Jørgensen 	 *
33014a1e7c0cSToke Høiland-Jørgensen 	 * - if prog->aux->dst_trampoline is set, the program was just loaded
33024a1e7c0cSToke Høiland-Jørgensen 	 *   and not yet attached to anything, so we can use the values stored
33034a1e7c0cSToke Høiland-Jørgensen 	 *   in prog->aux
33044a1e7c0cSToke Høiland-Jørgensen 	 *
33054a1e7c0cSToke Høiland-Jørgensen 	 * - if prog->aux->dst_trampoline is NULL, the program has already been
33064a1e7c0cSToke Høiland-Jørgensen          *   attached to a target and its initial target was cleared (below)
33074a1e7c0cSToke Høiland-Jørgensen 	 *
33084a1e7c0cSToke Høiland-Jørgensen 	 * - if tgt_prog != NULL, the caller specified tgt_prog_fd +
33094a1e7c0cSToke Høiland-Jørgensen 	 *   target_btf_id using the link_create API.
33104a1e7c0cSToke Høiland-Jørgensen 	 *
33114a1e7c0cSToke Høiland-Jørgensen 	 * - if tgt_prog == NULL when this function was called using the old
33124a1e7c0cSToke Høiland-Jørgensen 	 *   raw_tracepoint_open API, and we need a target from prog->aux
33134a1e7c0cSToke Høiland-Jørgensen 	 *
3314f3a95075SJiri Olsa 	 * - if prog->aux->dst_trampoline and tgt_prog is NULL, the program
3315f3a95075SJiri Olsa 	 *   was detached and is going for re-attachment.
3316715d82baSJiri Olsa 	 *
3317715d82baSJiri Olsa 	 * - if prog->aux->dst_trampoline is NULL and tgt_prog and prog->aux->attach_btf
3318715d82baSJiri Olsa 	 *   are NULL, then program was already attached and user did not provide
3319715d82baSJiri Olsa 	 *   tgt_prog_fd so we have no way to find out or create trampoline
33204a1e7c0cSToke Høiland-Jørgensen 	 */
33214a1e7c0cSToke Høiland-Jørgensen 	if (!prog->aux->dst_trampoline && !tgt_prog) {
3322f3a95075SJiri Olsa 		/*
3323f3a95075SJiri Olsa 		 * Allow re-attach for TRACING and LSM programs. If it's
3324f3a95075SJiri Olsa 		 * currently linked, bpf_trampoline_link_prog will fail.
3325f3a95075SJiri Olsa 		 * EXT programs need to specify tgt_prog_fd, so they
3326f3a95075SJiri Olsa 		 * re-attach in separate code path.
3327f3a95075SJiri Olsa 		 */
3328f3a95075SJiri Olsa 		if (prog->type != BPF_PROG_TYPE_TRACING &&
3329f3a95075SJiri Olsa 		    prog->type != BPF_PROG_TYPE_LSM) {
3330f3a95075SJiri Olsa 			err = -EINVAL;
33313aac1eadSToke Høiland-Jørgensen 			goto out_unlock;
33323aac1eadSToke Høiland-Jørgensen 		}
3333715d82baSJiri Olsa 		/* We can allow re-attach only if we have valid attach_btf. */
3334715d82baSJiri Olsa 		if (!prog->aux->attach_btf) {
3335715d82baSJiri Olsa 			err = -EINVAL;
3336715d82baSJiri Olsa 			goto out_unlock;
3337715d82baSJiri Olsa 		}
3338f3a95075SJiri Olsa 		btf_id = prog->aux->attach_btf_id;
3339f3a95075SJiri Olsa 		key = bpf_trampoline_compute_key(NULL, prog->aux->attach_btf, btf_id);
3340f3a95075SJiri Olsa 	}
33414a1e7c0cSToke Høiland-Jørgensen 
33424a1e7c0cSToke Høiland-Jørgensen 	if (!prog->aux->dst_trampoline ||
33434a1e7c0cSToke Høiland-Jørgensen 	    (key && key != prog->aux->dst_trampoline->key)) {
33444a1e7c0cSToke Høiland-Jørgensen 		/* If there is no saved target, or the specified target is
33454a1e7c0cSToke Høiland-Jørgensen 		 * different from the destination specified at load time, we
33464a1e7c0cSToke Høiland-Jørgensen 		 * need a new trampoline and a check for compatibility
33474a1e7c0cSToke Høiland-Jørgensen 		 */
33484a1e7c0cSToke Høiland-Jørgensen 		struct bpf_attach_target_info tgt_info = {};
33494a1e7c0cSToke Høiland-Jørgensen 
33504a1e7c0cSToke Høiland-Jørgensen 		err = bpf_check_attach_target(NULL, prog, tgt_prog, btf_id,
33514a1e7c0cSToke Høiland-Jørgensen 					      &tgt_info);
33524a1e7c0cSToke Høiland-Jørgensen 		if (err)
33534a1e7c0cSToke Høiland-Jørgensen 			goto out_unlock;
33544a1e7c0cSToke Høiland-Jørgensen 
335531bf1dbcSViktor Malik 		if (tgt_info.tgt_mod) {
335631bf1dbcSViktor Malik 			module_put(prog->aux->mod);
335731bf1dbcSViktor Malik 			prog->aux->mod = tgt_info.tgt_mod;
335831bf1dbcSViktor Malik 		}
335931bf1dbcSViktor Malik 
33604a1e7c0cSToke Høiland-Jørgensen 		tr = bpf_trampoline_get(key, &tgt_info);
33614a1e7c0cSToke Høiland-Jørgensen 		if (!tr) {
33624a1e7c0cSToke Høiland-Jørgensen 			err = -ENOMEM;
33634a1e7c0cSToke Høiland-Jørgensen 			goto out_unlock;
33644a1e7c0cSToke Høiland-Jørgensen 		}
33654a1e7c0cSToke Høiland-Jørgensen 	} else {
33664a1e7c0cSToke Høiland-Jørgensen 		/* The caller didn't specify a target, or the target was the
33674a1e7c0cSToke Høiland-Jørgensen 		 * same as the destination supplied during program load. This
33684a1e7c0cSToke Høiland-Jørgensen 		 * means we can reuse the trampoline and reference from program
33694a1e7c0cSToke Høiland-Jørgensen 		 * load time, and there is no need to allocate a new one. This
33704a1e7c0cSToke Høiland-Jørgensen 		 * can only happen once for any program, as the saved values in
33714a1e7c0cSToke Høiland-Jørgensen 		 * prog->aux are cleared below.
33724a1e7c0cSToke Høiland-Jørgensen 		 */
33733aac1eadSToke Høiland-Jørgensen 		tr = prog->aux->dst_trampoline;
33743aac1eadSToke Høiland-Jørgensen 		tgt_prog = prog->aux->dst_prog;
33754a1e7c0cSToke Høiland-Jørgensen 	}
33763aac1eadSToke Høiland-Jørgensen 
3377f7e0beafSKui-Feng Lee 	err = bpf_link_prime(&link->link.link, &link_primer);
33783aac1eadSToke Høiland-Jørgensen 	if (err)
33793aac1eadSToke Høiland-Jørgensen 		goto out_unlock;
33803aac1eadSToke Høiland-Jørgensen 
3381f7e0beafSKui-Feng Lee 	err = bpf_trampoline_link_prog(&link->link, tr);
3382babf3164SAndrii Nakryiko 	if (err) {
3383a3b80e10SAndrii Nakryiko 		bpf_link_cleanup(&link_primer);
33843aac1eadSToke Høiland-Jørgensen 		link = NULL;
33853aac1eadSToke Høiland-Jørgensen 		goto out_unlock;
3386babf3164SAndrii Nakryiko 	}
3387babf3164SAndrii Nakryiko 
33883aac1eadSToke Høiland-Jørgensen 	link->tgt_prog = tgt_prog;
33893aac1eadSToke Høiland-Jørgensen 	link->trampoline = tr;
33903aac1eadSToke Høiland-Jørgensen 
33914a1e7c0cSToke Høiland-Jørgensen 	/* Always clear the trampoline and target prog from prog->aux to make
33924a1e7c0cSToke Høiland-Jørgensen 	 * sure the original attach destination is not kept alive after a
33934a1e7c0cSToke Høiland-Jørgensen 	 * program is (re-)attached to another target.
33944a1e7c0cSToke Høiland-Jørgensen 	 */
33954a1e7c0cSToke Høiland-Jørgensen 	if (prog->aux->dst_prog &&
33964a1e7c0cSToke Høiland-Jørgensen 	    (tgt_prog_fd || tr != prog->aux->dst_trampoline))
33974a1e7c0cSToke Høiland-Jørgensen 		/* got extra prog ref from syscall, or attaching to different prog */
33984a1e7c0cSToke Høiland-Jørgensen 		bpf_prog_put(prog->aux->dst_prog);
33994a1e7c0cSToke Høiland-Jørgensen 	if (prog->aux->dst_trampoline && tr != prog->aux->dst_trampoline)
34004a1e7c0cSToke Høiland-Jørgensen 		/* we allocated a new trampoline, so free the old one */
34014a1e7c0cSToke Høiland-Jørgensen 		bpf_trampoline_put(prog->aux->dst_trampoline);
34024a1e7c0cSToke Høiland-Jørgensen 
34033aac1eadSToke Høiland-Jørgensen 	prog->aux->dst_prog = NULL;
34043aac1eadSToke Høiland-Jørgensen 	prog->aux->dst_trampoline = NULL;
34053aac1eadSToke Høiland-Jørgensen 	mutex_unlock(&prog->aux->dst_mutex);
34063aac1eadSToke Høiland-Jørgensen 
3407a3b80e10SAndrii Nakryiko 	return bpf_link_settle(&link_primer);
34083aac1eadSToke Høiland-Jørgensen out_unlock:
34094a1e7c0cSToke Høiland-Jørgensen 	if (tr && tr != prog->aux->dst_trampoline)
34104a1e7c0cSToke Høiland-Jørgensen 		bpf_trampoline_put(tr);
34113aac1eadSToke Høiland-Jørgensen 	mutex_unlock(&prog->aux->dst_mutex);
34123aac1eadSToke Høiland-Jørgensen 	kfree(link);
3413fec56f58SAlexei Starovoitov out_put_prog:
34144a1e7c0cSToke Høiland-Jørgensen 	if (tgt_prog_fd && tgt_prog)
34154a1e7c0cSToke Høiland-Jørgensen 		bpf_prog_put(tgt_prog);
3416fec56f58SAlexei Starovoitov 	return err;
3417fec56f58SAlexei Starovoitov }
3418fec56f58SAlexei Starovoitov 
341970ed506cSAndrii Nakryiko struct bpf_raw_tp_link {
342070ed506cSAndrii Nakryiko 	struct bpf_link link;
3421c4f6699dSAlexei Starovoitov 	struct bpf_raw_event_map *btp;
3422c4f6699dSAlexei Starovoitov };
3423c4f6699dSAlexei Starovoitov 
342470ed506cSAndrii Nakryiko static void bpf_raw_tp_link_release(struct bpf_link *link)
3425c4f6699dSAlexei Starovoitov {
342670ed506cSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp =
342770ed506cSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3428c4f6699dSAlexei Starovoitov 
342970ed506cSAndrii Nakryiko 	bpf_probe_unregister(raw_tp->btp, raw_tp->link.prog);
3430a38d1107SMatt Mullins 	bpf_put_raw_tracepoint(raw_tp->btp);
3431babf3164SAndrii Nakryiko }
3432babf3164SAndrii Nakryiko 
3433babf3164SAndrii Nakryiko static void bpf_raw_tp_link_dealloc(struct bpf_link *link)
3434babf3164SAndrii Nakryiko {
3435babf3164SAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp =
3436babf3164SAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3437babf3164SAndrii Nakryiko 
3438c4f6699dSAlexei Starovoitov 	kfree(raw_tp);
3439c4f6699dSAlexei Starovoitov }
3440c4f6699dSAlexei Starovoitov 
3441f2e10bffSAndrii Nakryiko static void bpf_raw_tp_link_show_fdinfo(const struct bpf_link *link,
3442f2e10bffSAndrii Nakryiko 					struct seq_file *seq)
3443f2e10bffSAndrii Nakryiko {
3444f2e10bffSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp_link =
3445f2e10bffSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3446f2e10bffSAndrii Nakryiko 
3447f2e10bffSAndrii Nakryiko 	seq_printf(seq,
3448f2e10bffSAndrii Nakryiko 		   "tp_name:\t%s\n",
3449f2e10bffSAndrii Nakryiko 		   raw_tp_link->btp->tp->name);
3450f2e10bffSAndrii Nakryiko }
3451f2e10bffSAndrii Nakryiko 
345257d48537SYafang Shao static int bpf_copy_to_user(char __user *ubuf, const char *buf, u32 ulen,
345357d48537SYafang Shao 			    u32 len)
345457d48537SYafang Shao {
345557d48537SYafang Shao 	if (ulen >= len + 1) {
345657d48537SYafang Shao 		if (copy_to_user(ubuf, buf, len + 1))
345757d48537SYafang Shao 			return -EFAULT;
345857d48537SYafang Shao 	} else {
345957d48537SYafang Shao 		char zero = '\0';
346057d48537SYafang Shao 
346157d48537SYafang Shao 		if (copy_to_user(ubuf, buf, ulen - 1))
346257d48537SYafang Shao 			return -EFAULT;
346357d48537SYafang Shao 		if (put_user(zero, ubuf + ulen - 1))
346457d48537SYafang Shao 			return -EFAULT;
346557d48537SYafang Shao 		return -ENOSPC;
346657d48537SYafang Shao 	}
346757d48537SYafang Shao 
346857d48537SYafang Shao 	return 0;
346957d48537SYafang Shao }
347057d48537SYafang Shao 
3471f2e10bffSAndrii Nakryiko static int bpf_raw_tp_link_fill_link_info(const struct bpf_link *link,
3472f2e10bffSAndrii Nakryiko 					  struct bpf_link_info *info)
3473f2e10bffSAndrii Nakryiko {
3474f2e10bffSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp_link =
3475f2e10bffSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3476f2e10bffSAndrii Nakryiko 	char __user *ubuf = u64_to_user_ptr(info->raw_tracepoint.tp_name);
3477f2e10bffSAndrii Nakryiko 	const char *tp_name = raw_tp_link->btp->tp->name;
3478f2e10bffSAndrii Nakryiko 	u32 ulen = info->raw_tracepoint.tp_name_len;
3479f2e10bffSAndrii Nakryiko 	size_t tp_len = strlen(tp_name);
3480f2e10bffSAndrii Nakryiko 
3481b474959dSYonghong Song 	if (!ulen ^ !ubuf)
3482f2e10bffSAndrii Nakryiko 		return -EINVAL;
3483f2e10bffSAndrii Nakryiko 
3484f2e10bffSAndrii Nakryiko 	info->raw_tracepoint.tp_name_len = tp_len + 1;
3485f2e10bffSAndrii Nakryiko 
3486f2e10bffSAndrii Nakryiko 	if (!ubuf)
3487f2e10bffSAndrii Nakryiko 		return 0;
3488f2e10bffSAndrii Nakryiko 
348957d48537SYafang Shao 	return bpf_copy_to_user(ubuf, tp_name, ulen, tp_len);
3490f2e10bffSAndrii Nakryiko }
3491f2e10bffSAndrii Nakryiko 
3492a3b80e10SAndrii Nakryiko static const struct bpf_link_ops bpf_raw_tp_link_lops = {
349370ed506cSAndrii Nakryiko 	.release = bpf_raw_tp_link_release,
3494babf3164SAndrii Nakryiko 	.dealloc = bpf_raw_tp_link_dealloc,
3495f2e10bffSAndrii Nakryiko 	.show_fdinfo = bpf_raw_tp_link_show_fdinfo,
3496f2e10bffSAndrii Nakryiko 	.fill_link_info = bpf_raw_tp_link_fill_link_info,
3497c4f6699dSAlexei Starovoitov };
3498c4f6699dSAlexei Starovoitov 
3499b89fbfbbSAndrii Nakryiko #ifdef CONFIG_PERF_EVENTS
3500b89fbfbbSAndrii Nakryiko struct bpf_perf_link {
3501b89fbfbbSAndrii Nakryiko 	struct bpf_link link;
3502b89fbfbbSAndrii Nakryiko 	struct file *perf_file;
3503b89fbfbbSAndrii Nakryiko };
3504b89fbfbbSAndrii Nakryiko 
3505b89fbfbbSAndrii Nakryiko static void bpf_perf_link_release(struct bpf_link *link)
3506b89fbfbbSAndrii Nakryiko {
3507b89fbfbbSAndrii Nakryiko 	struct bpf_perf_link *perf_link = container_of(link, struct bpf_perf_link, link);
3508b89fbfbbSAndrii Nakryiko 	struct perf_event *event = perf_link->perf_file->private_data;
3509b89fbfbbSAndrii Nakryiko 
3510b89fbfbbSAndrii Nakryiko 	perf_event_free_bpf_prog(event);
3511b89fbfbbSAndrii Nakryiko 	fput(perf_link->perf_file);
3512b89fbfbbSAndrii Nakryiko }
3513b89fbfbbSAndrii Nakryiko 
3514b89fbfbbSAndrii Nakryiko static void bpf_perf_link_dealloc(struct bpf_link *link)
3515b89fbfbbSAndrii Nakryiko {
3516b89fbfbbSAndrii Nakryiko 	struct bpf_perf_link *perf_link = container_of(link, struct bpf_perf_link, link);
3517b89fbfbbSAndrii Nakryiko 
3518b89fbfbbSAndrii Nakryiko 	kfree(perf_link);
3519b89fbfbbSAndrii Nakryiko }
3520b89fbfbbSAndrii Nakryiko 
35211b715e1bSYafang Shao static int bpf_perf_link_fill_common(const struct perf_event *event,
35221b715e1bSYafang Shao 				     char __user *uname, u32 ulen,
35231b715e1bSYafang Shao 				     u64 *probe_offset, u64 *probe_addr,
35243acf8aceSJiri Olsa 				     u32 *fd_type, unsigned long *missed)
35251b715e1bSYafang Shao {
35261b715e1bSYafang Shao 	const char *buf;
35271b715e1bSYafang Shao 	u32 prog_id;
35281b715e1bSYafang Shao 	size_t len;
35291b715e1bSYafang Shao 	int err;
35301b715e1bSYafang Shao 
35311b715e1bSYafang Shao 	if (!ulen ^ !uname)
35321b715e1bSYafang Shao 		return -EINVAL;
35331b715e1bSYafang Shao 
35341b715e1bSYafang Shao 	err = bpf_get_perf_event_info(event, &prog_id, fd_type, &buf,
35353acf8aceSJiri Olsa 				      probe_offset, probe_addr, missed);
35361b715e1bSYafang Shao 	if (err)
35371b715e1bSYafang Shao 		return err;
35380aa35162SYafang Shao 	if (!uname)
35390aa35162SYafang Shao 		return 0;
35401b715e1bSYafang Shao 	if (buf) {
35411b715e1bSYafang Shao 		len = strlen(buf);
35421b715e1bSYafang Shao 		err = bpf_copy_to_user(uname, buf, ulen, len);
35431b715e1bSYafang Shao 		if (err)
35441b715e1bSYafang Shao 			return err;
35451b715e1bSYafang Shao 	} else {
35461b715e1bSYafang Shao 		char zero = '\0';
35471b715e1bSYafang Shao 
35481b715e1bSYafang Shao 		if (put_user(zero, uname))
35491b715e1bSYafang Shao 			return -EFAULT;
35501b715e1bSYafang Shao 	}
35511b715e1bSYafang Shao 	return 0;
35521b715e1bSYafang Shao }
35531b715e1bSYafang Shao 
35541b715e1bSYafang Shao #ifdef CONFIG_KPROBE_EVENTS
35551b715e1bSYafang Shao static int bpf_perf_link_fill_kprobe(const struct perf_event *event,
35561b715e1bSYafang Shao 				     struct bpf_link_info *info)
35571b715e1bSYafang Shao {
35583acf8aceSJiri Olsa 	unsigned long missed;
35591b715e1bSYafang Shao 	char __user *uname;
35601b715e1bSYafang Shao 	u64 addr, offset;
35611b715e1bSYafang Shao 	u32 ulen, type;
35621b715e1bSYafang Shao 	int err;
35631b715e1bSYafang Shao 
35641b715e1bSYafang Shao 	uname = u64_to_user_ptr(info->perf_event.kprobe.func_name);
35651b715e1bSYafang Shao 	ulen = info->perf_event.kprobe.name_len;
35661b715e1bSYafang Shao 	err = bpf_perf_link_fill_common(event, uname, ulen, &offset, &addr,
35673acf8aceSJiri Olsa 					&type, &missed);
35681b715e1bSYafang Shao 	if (err)
35691b715e1bSYafang Shao 		return err;
35701b715e1bSYafang Shao 	if (type == BPF_FD_TYPE_KRETPROBE)
35711b715e1bSYafang Shao 		info->perf_event.type = BPF_PERF_EVENT_KRETPROBE;
35721b715e1bSYafang Shao 	else
35731b715e1bSYafang Shao 		info->perf_event.type = BPF_PERF_EVENT_KPROBE;
35741b715e1bSYafang Shao 
35751b715e1bSYafang Shao 	info->perf_event.kprobe.offset = offset;
35763acf8aceSJiri Olsa 	info->perf_event.kprobe.missed = missed;
35771b715e1bSYafang Shao 	if (!kallsyms_show_value(current_cred()))
35781b715e1bSYafang Shao 		addr = 0;
35791b715e1bSYafang Shao 	info->perf_event.kprobe.addr = addr;
3580d5c16492SJiri Olsa 	info->perf_event.kprobe.cookie = event->bpf_cookie;
35811b715e1bSYafang Shao 	return 0;
35821b715e1bSYafang Shao }
35831b715e1bSYafang Shao #endif
35841b715e1bSYafang Shao 
35851b715e1bSYafang Shao #ifdef CONFIG_UPROBE_EVENTS
35861b715e1bSYafang Shao static int bpf_perf_link_fill_uprobe(const struct perf_event *event,
35871b715e1bSYafang Shao 				     struct bpf_link_info *info)
35881b715e1bSYafang Shao {
35891b715e1bSYafang Shao 	char __user *uname;
35901b715e1bSYafang Shao 	u64 addr, offset;
35911b715e1bSYafang Shao 	u32 ulen, type;
35921b715e1bSYafang Shao 	int err;
35931b715e1bSYafang Shao 
35941b715e1bSYafang Shao 	uname = u64_to_user_ptr(info->perf_event.uprobe.file_name);
35951b715e1bSYafang Shao 	ulen = info->perf_event.uprobe.name_len;
35961b715e1bSYafang Shao 	err = bpf_perf_link_fill_common(event, uname, ulen, &offset, &addr,
35973acf8aceSJiri Olsa 					&type, NULL);
35981b715e1bSYafang Shao 	if (err)
35991b715e1bSYafang Shao 		return err;
36001b715e1bSYafang Shao 
36011b715e1bSYafang Shao 	if (type == BPF_FD_TYPE_URETPROBE)
36021b715e1bSYafang Shao 		info->perf_event.type = BPF_PERF_EVENT_URETPROBE;
36031b715e1bSYafang Shao 	else
36041b715e1bSYafang Shao 		info->perf_event.type = BPF_PERF_EVENT_UPROBE;
36051b715e1bSYafang Shao 	info->perf_event.uprobe.offset = offset;
3606d5c16492SJiri Olsa 	info->perf_event.uprobe.cookie = event->bpf_cookie;
36071b715e1bSYafang Shao 	return 0;
36081b715e1bSYafang Shao }
36091b715e1bSYafang Shao #endif
36101b715e1bSYafang Shao 
36111b715e1bSYafang Shao static int bpf_perf_link_fill_probe(const struct perf_event *event,
36121b715e1bSYafang Shao 				    struct bpf_link_info *info)
36131b715e1bSYafang Shao {
36141b715e1bSYafang Shao #ifdef CONFIG_KPROBE_EVENTS
36151b715e1bSYafang Shao 	if (event->tp_event->flags & TRACE_EVENT_FL_KPROBE)
36161b715e1bSYafang Shao 		return bpf_perf_link_fill_kprobe(event, info);
36171b715e1bSYafang Shao #endif
36181b715e1bSYafang Shao #ifdef CONFIG_UPROBE_EVENTS
36191b715e1bSYafang Shao 	if (event->tp_event->flags & TRACE_EVENT_FL_UPROBE)
36201b715e1bSYafang Shao 		return bpf_perf_link_fill_uprobe(event, info);
36211b715e1bSYafang Shao #endif
36221b715e1bSYafang Shao 	return -EOPNOTSUPP;
36231b715e1bSYafang Shao }
36241b715e1bSYafang Shao 
36251b715e1bSYafang Shao static int bpf_perf_link_fill_tracepoint(const struct perf_event *event,
36261b715e1bSYafang Shao 					 struct bpf_link_info *info)
36271b715e1bSYafang Shao {
36281b715e1bSYafang Shao 	char __user *uname;
36291b715e1bSYafang Shao 	u32 ulen;
36301b715e1bSYafang Shao 
36311b715e1bSYafang Shao 	uname = u64_to_user_ptr(info->perf_event.tracepoint.tp_name);
36321b715e1bSYafang Shao 	ulen = info->perf_event.tracepoint.name_len;
36331b715e1bSYafang Shao 	info->perf_event.type = BPF_PERF_EVENT_TRACEPOINT;
3634d5c16492SJiri Olsa 	info->perf_event.tracepoint.cookie = event->bpf_cookie;
36353acf8aceSJiri Olsa 	return bpf_perf_link_fill_common(event, uname, ulen, NULL, NULL, NULL, NULL);
36361b715e1bSYafang Shao }
36371b715e1bSYafang Shao 
36381b715e1bSYafang Shao static int bpf_perf_link_fill_perf_event(const struct perf_event *event,
36391b715e1bSYafang Shao 					 struct bpf_link_info *info)
36401b715e1bSYafang Shao {
36411b715e1bSYafang Shao 	info->perf_event.event.type = event->attr.type;
36421b715e1bSYafang Shao 	info->perf_event.event.config = event->attr.config;
3643d5c16492SJiri Olsa 	info->perf_event.event.cookie = event->bpf_cookie;
36441b715e1bSYafang Shao 	info->perf_event.type = BPF_PERF_EVENT_EVENT;
36451b715e1bSYafang Shao 	return 0;
36461b715e1bSYafang Shao }
36471b715e1bSYafang Shao 
36481b715e1bSYafang Shao static int bpf_perf_link_fill_link_info(const struct bpf_link *link,
36491b715e1bSYafang Shao 					struct bpf_link_info *info)
36501b715e1bSYafang Shao {
36511b715e1bSYafang Shao 	struct bpf_perf_link *perf_link;
36521b715e1bSYafang Shao 	const struct perf_event *event;
36531b715e1bSYafang Shao 
36541b715e1bSYafang Shao 	perf_link = container_of(link, struct bpf_perf_link, link);
36551b715e1bSYafang Shao 	event = perf_get_event(perf_link->perf_file);
36561b715e1bSYafang Shao 	if (IS_ERR(event))
36571b715e1bSYafang Shao 		return PTR_ERR(event);
36581b715e1bSYafang Shao 
36591b715e1bSYafang Shao 	switch (event->prog->type) {
36601b715e1bSYafang Shao 	case BPF_PROG_TYPE_PERF_EVENT:
36611b715e1bSYafang Shao 		return bpf_perf_link_fill_perf_event(event, info);
36621b715e1bSYafang Shao 	case BPF_PROG_TYPE_TRACEPOINT:
36631b715e1bSYafang Shao 		return bpf_perf_link_fill_tracepoint(event, info);
36641b715e1bSYafang Shao 	case BPF_PROG_TYPE_KPROBE:
36651b715e1bSYafang Shao 		return bpf_perf_link_fill_probe(event, info);
36661b715e1bSYafang Shao 	default:
36671b715e1bSYafang Shao 		return -EOPNOTSUPP;
36681b715e1bSYafang Shao 	}
36691b715e1bSYafang Shao }
36701b715e1bSYafang Shao 
3671b89fbfbbSAndrii Nakryiko static const struct bpf_link_ops bpf_perf_link_lops = {
3672b89fbfbbSAndrii Nakryiko 	.release = bpf_perf_link_release,
3673b89fbfbbSAndrii Nakryiko 	.dealloc = bpf_perf_link_dealloc,
36741b715e1bSYafang Shao 	.fill_link_info = bpf_perf_link_fill_link_info,
3675b89fbfbbSAndrii Nakryiko };
3676b89fbfbbSAndrii Nakryiko 
3677b89fbfbbSAndrii Nakryiko static int bpf_perf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
3678b89fbfbbSAndrii Nakryiko {
3679b89fbfbbSAndrii Nakryiko 	struct bpf_link_primer link_primer;
3680b89fbfbbSAndrii Nakryiko 	struct bpf_perf_link *link;
3681b89fbfbbSAndrii Nakryiko 	struct perf_event *event;
3682b89fbfbbSAndrii Nakryiko 	struct file *perf_file;
3683b89fbfbbSAndrii Nakryiko 	int err;
3684b89fbfbbSAndrii Nakryiko 
3685b89fbfbbSAndrii Nakryiko 	if (attr->link_create.flags)
3686b89fbfbbSAndrii Nakryiko 		return -EINVAL;
3687b89fbfbbSAndrii Nakryiko 
3688b89fbfbbSAndrii Nakryiko 	perf_file = perf_event_get(attr->link_create.target_fd);
3689b89fbfbbSAndrii Nakryiko 	if (IS_ERR(perf_file))
3690b89fbfbbSAndrii Nakryiko 		return PTR_ERR(perf_file);
3691b89fbfbbSAndrii Nakryiko 
3692b89fbfbbSAndrii Nakryiko 	link = kzalloc(sizeof(*link), GFP_USER);
3693b89fbfbbSAndrii Nakryiko 	if (!link) {
3694b89fbfbbSAndrii Nakryiko 		err = -ENOMEM;
3695b89fbfbbSAndrii Nakryiko 		goto out_put_file;
3696b89fbfbbSAndrii Nakryiko 	}
3697b89fbfbbSAndrii Nakryiko 	bpf_link_init(&link->link, BPF_LINK_TYPE_PERF_EVENT, &bpf_perf_link_lops, prog);
3698b89fbfbbSAndrii Nakryiko 	link->perf_file = perf_file;
3699b89fbfbbSAndrii Nakryiko 
3700b89fbfbbSAndrii Nakryiko 	err = bpf_link_prime(&link->link, &link_primer);
3701b89fbfbbSAndrii Nakryiko 	if (err) {
3702b89fbfbbSAndrii Nakryiko 		kfree(link);
3703b89fbfbbSAndrii Nakryiko 		goto out_put_file;
3704b89fbfbbSAndrii Nakryiko 	}
3705b89fbfbbSAndrii Nakryiko 
3706b89fbfbbSAndrii Nakryiko 	event = perf_file->private_data;
370782e6b1eeSAndrii Nakryiko 	err = perf_event_set_bpf_prog(event, prog, attr->link_create.perf_event.bpf_cookie);
3708b89fbfbbSAndrii Nakryiko 	if (err) {
3709b89fbfbbSAndrii Nakryiko 		bpf_link_cleanup(&link_primer);
3710b89fbfbbSAndrii Nakryiko 		goto out_put_file;
3711b89fbfbbSAndrii Nakryiko 	}
3712b89fbfbbSAndrii Nakryiko 	/* perf_event_set_bpf_prog() doesn't take its own refcnt on prog */
3713b89fbfbbSAndrii Nakryiko 	bpf_prog_inc(prog);
3714b89fbfbbSAndrii Nakryiko 
3715b89fbfbbSAndrii Nakryiko 	return bpf_link_settle(&link_primer);
3716b89fbfbbSAndrii Nakryiko 
3717b89fbfbbSAndrii Nakryiko out_put_file:
3718b89fbfbbSAndrii Nakryiko 	fput(perf_file);
3719b89fbfbbSAndrii Nakryiko 	return err;
3720b89fbfbbSAndrii Nakryiko }
37210dcac272SJiri Olsa #else
37220dcac272SJiri Olsa static int bpf_perf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
37230dcac272SJiri Olsa {
37240dcac272SJiri Olsa 	return -EOPNOTSUPP;
37250dcac272SJiri Olsa }
3726b89fbfbbSAndrii Nakryiko #endif /* CONFIG_PERF_EVENTS */
3727b89fbfbbSAndrii Nakryiko 
3728df86ca0dSAndrii Nakryiko static int bpf_raw_tp_link_attach(struct bpf_prog *prog,
3729df86ca0dSAndrii Nakryiko 				  const char __user *user_tp_name)
3730c4f6699dSAlexei Starovoitov {
3731a3b80e10SAndrii Nakryiko 	struct bpf_link_primer link_primer;
3732babf3164SAndrii Nakryiko 	struct bpf_raw_tp_link *link;
3733c4f6699dSAlexei Starovoitov 	struct bpf_raw_event_map *btp;
3734ac4414b5SAlexei Starovoitov 	const char *tp_name;
3735ac4414b5SAlexei Starovoitov 	char buf[128];
3736a3b80e10SAndrii Nakryiko 	int err;
3737c4f6699dSAlexei Starovoitov 
37389e4e01dfSKP Singh 	switch (prog->type) {
37399e4e01dfSKP Singh 	case BPF_PROG_TYPE_TRACING:
37409e4e01dfSKP Singh 	case BPF_PROG_TYPE_EXT:
37419e4e01dfSKP Singh 	case BPF_PROG_TYPE_LSM:
3742df86ca0dSAndrii Nakryiko 		if (user_tp_name)
3743fec56f58SAlexei Starovoitov 			/* The attach point for this category of programs
3744fec56f58SAlexei Starovoitov 			 * should be specified via btf_id during program load.
3745ac4414b5SAlexei Starovoitov 			 */
3746df86ca0dSAndrii Nakryiko 			return -EINVAL;
37479e4e01dfSKP Singh 		if (prog->type == BPF_PROG_TYPE_TRACING &&
37489e4e01dfSKP Singh 		    prog->expected_attach_type == BPF_TRACE_RAW_TP) {
374938207291SMartin KaFai Lau 			tp_name = prog->aux->attach_func_name;
37509e4e01dfSKP Singh 			break;
37519e4e01dfSKP Singh 		}
37522fcc8241SKui-Feng Lee 		return bpf_tracing_prog_attach(prog, 0, 0, 0);
37539e4e01dfSKP Singh 	case BPF_PROG_TYPE_RAW_TRACEPOINT:
37549e4e01dfSKP Singh 	case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
3755df86ca0dSAndrii Nakryiko 		if (strncpy_from_user(buf, user_tp_name, sizeof(buf) - 1) < 0)
3756df86ca0dSAndrii Nakryiko 			return -EFAULT;
3757ac4414b5SAlexei Starovoitov 		buf[sizeof(buf) - 1] = 0;
3758ac4414b5SAlexei Starovoitov 		tp_name = buf;
37599e4e01dfSKP Singh 		break;
37609e4e01dfSKP Singh 	default:
3761df86ca0dSAndrii Nakryiko 		return -EINVAL;
3762ac4414b5SAlexei Starovoitov 	}
3763c4f6699dSAlexei Starovoitov 
3764a38d1107SMatt Mullins 	btp = bpf_get_raw_tracepoint(tp_name);
3765df86ca0dSAndrii Nakryiko 	if (!btp)
3766df86ca0dSAndrii Nakryiko 		return -ENOENT;
3767c4f6699dSAlexei Starovoitov 
3768babf3164SAndrii Nakryiko 	link = kzalloc(sizeof(*link), GFP_USER);
3769babf3164SAndrii Nakryiko 	if (!link) {
3770a38d1107SMatt Mullins 		err = -ENOMEM;
3771a38d1107SMatt Mullins 		goto out_put_btp;
3772a38d1107SMatt Mullins 	}
3773f2e10bffSAndrii Nakryiko 	bpf_link_init(&link->link, BPF_LINK_TYPE_RAW_TRACEPOINT,
3774f2e10bffSAndrii Nakryiko 		      &bpf_raw_tp_link_lops, prog);
3775babf3164SAndrii Nakryiko 	link->btp = btp;
3776c4f6699dSAlexei Starovoitov 
3777a3b80e10SAndrii Nakryiko 	err = bpf_link_prime(&link->link, &link_primer);
3778a3b80e10SAndrii Nakryiko 	if (err) {
3779babf3164SAndrii Nakryiko 		kfree(link);
3780babf3164SAndrii Nakryiko 		goto out_put_btp;
3781c4f6699dSAlexei Starovoitov 	}
3782babf3164SAndrii Nakryiko 
3783babf3164SAndrii Nakryiko 	err = bpf_probe_register(link->btp, prog);
3784babf3164SAndrii Nakryiko 	if (err) {
3785a3b80e10SAndrii Nakryiko 		bpf_link_cleanup(&link_primer);
3786babf3164SAndrii Nakryiko 		goto out_put_btp;
3787babf3164SAndrii Nakryiko 	}
3788babf3164SAndrii Nakryiko 
3789a3b80e10SAndrii Nakryiko 	return bpf_link_settle(&link_primer);
3790c4f6699dSAlexei Starovoitov 
3791a38d1107SMatt Mullins out_put_btp:
3792a38d1107SMatt Mullins 	bpf_put_raw_tracepoint(btp);
3793c4f6699dSAlexei Starovoitov 	return err;
3794c4f6699dSAlexei Starovoitov }
3795c4f6699dSAlexei Starovoitov 
3796df86ca0dSAndrii Nakryiko #define BPF_RAW_TRACEPOINT_OPEN_LAST_FIELD raw_tracepoint.prog_fd
3797df86ca0dSAndrii Nakryiko 
3798df86ca0dSAndrii Nakryiko static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
3799df86ca0dSAndrii Nakryiko {
3800df86ca0dSAndrii Nakryiko 	struct bpf_prog *prog;
3801df86ca0dSAndrii Nakryiko 	int fd;
3802df86ca0dSAndrii Nakryiko 
3803df86ca0dSAndrii Nakryiko 	if (CHECK_ATTR(BPF_RAW_TRACEPOINT_OPEN))
3804df86ca0dSAndrii Nakryiko 		return -EINVAL;
3805df86ca0dSAndrii Nakryiko 
3806df86ca0dSAndrii Nakryiko 	prog = bpf_prog_get(attr->raw_tracepoint.prog_fd);
3807df86ca0dSAndrii Nakryiko 	if (IS_ERR(prog))
3808df86ca0dSAndrii Nakryiko 		return PTR_ERR(prog);
3809df86ca0dSAndrii Nakryiko 
3810df86ca0dSAndrii Nakryiko 	fd = bpf_raw_tp_link_attach(prog, u64_to_user_ptr(attr->raw_tracepoint.name));
3811df86ca0dSAndrii Nakryiko 	if (fd < 0)
3812df86ca0dSAndrii Nakryiko 		bpf_prog_put(prog);
3813df86ca0dSAndrii Nakryiko 	return fd;
3814df86ca0dSAndrii Nakryiko }
3815df86ca0dSAndrii Nakryiko 
3816e28784e3SAndrii Nakryiko static enum bpf_prog_type
3817e28784e3SAndrii Nakryiko attach_type_to_prog_type(enum bpf_attach_type attach_type)
3818e28784e3SAndrii Nakryiko {
3819e28784e3SAndrii Nakryiko 	switch (attach_type) {
3820e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_INGRESS:
3821e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_EGRESS:
3822e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SKB;
3823e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_SOCK_CREATE:
3824f5836749SStanislav Fomichev 	case BPF_CGROUP_INET_SOCK_RELEASE:
3825e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_POST_BIND:
3826e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_POST_BIND:
3827e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCK;
3828e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_BIND:
3829e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_BIND:
3830e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_CONNECT:
3831e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_CONNECT:
3832859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_CONNECT:
38331b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETPEERNAME:
38341b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETPEERNAME:
3835859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_GETPEERNAME:
38361b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETSOCKNAME:
38371b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETSOCKNAME:
3838859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_GETSOCKNAME:
3839e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP4_SENDMSG:
3840e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP6_SENDMSG:
3841859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_SENDMSG:
3842e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP4_RECVMSG:
3843e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP6_RECVMSG:
3844859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_RECVMSG:
3845e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
3846e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SOCK_OPS:
3847e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SOCK_OPS;
3848e28784e3SAndrii Nakryiko 	case BPF_CGROUP_DEVICE:
3849e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_DEVICE;
3850e28784e3SAndrii Nakryiko 	case BPF_SK_MSG_VERDICT:
3851e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SK_MSG;
3852e28784e3SAndrii Nakryiko 	case BPF_SK_SKB_STREAM_PARSER:
3853e28784e3SAndrii Nakryiko 	case BPF_SK_SKB_STREAM_VERDICT:
3854a7ba4558SCong Wang 	case BPF_SK_SKB_VERDICT:
3855e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SK_SKB;
3856e28784e3SAndrii Nakryiko 	case BPF_LIRC_MODE2:
3857e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_LIRC_MODE2;
3858e28784e3SAndrii Nakryiko 	case BPF_FLOW_DISSECTOR:
3859e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_FLOW_DISSECTOR;
3860e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SYSCTL:
3861e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SYSCTL;
3862e28784e3SAndrii Nakryiko 	case BPF_CGROUP_GETSOCKOPT:
3863e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SETSOCKOPT:
3864e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCKOPT;
3865de4e05caSYonghong Song 	case BPF_TRACE_ITER:
3866df86ca0dSAndrii Nakryiko 	case BPF_TRACE_RAW_TP:
3867df86ca0dSAndrii Nakryiko 	case BPF_TRACE_FENTRY:
3868df86ca0dSAndrii Nakryiko 	case BPF_TRACE_FEXIT:
3869df86ca0dSAndrii Nakryiko 	case BPF_MODIFY_RETURN:
3870de4e05caSYonghong Song 		return BPF_PROG_TYPE_TRACING;
3871df86ca0dSAndrii Nakryiko 	case BPF_LSM_MAC:
3872df86ca0dSAndrii Nakryiko 		return BPF_PROG_TYPE_LSM;
3873e9ddbb77SJakub Sitnicki 	case BPF_SK_LOOKUP:
3874e9ddbb77SJakub Sitnicki 		return BPF_PROG_TYPE_SK_LOOKUP;
3875aa8d3a71SAndrii Nakryiko 	case BPF_XDP:
3876aa8d3a71SAndrii Nakryiko 		return BPF_PROG_TYPE_XDP;
387769fd337aSStanislav Fomichev 	case BPF_LSM_CGROUP:
387869fd337aSStanislav Fomichev 		return BPF_PROG_TYPE_LSM;
3879e420bed0SDaniel Borkmann 	case BPF_TCX_INGRESS:
3880e420bed0SDaniel Borkmann 	case BPF_TCX_EGRESS:
388135dfaad7SDaniel Borkmann 	case BPF_NETKIT_PRIMARY:
388235dfaad7SDaniel Borkmann 	case BPF_NETKIT_PEER:
3883e420bed0SDaniel Borkmann 		return BPF_PROG_TYPE_SCHED_CLS;
3884e28784e3SAndrii Nakryiko 	default:
3885e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_UNSPEC;
3886e28784e3SAndrii Nakryiko 	}
3887e28784e3SAndrii Nakryiko }
3888e28784e3SAndrii Nakryiko 
38893505cb9fSJiri Olsa static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog,
38903505cb9fSJiri Olsa 					     enum bpf_attach_type attach_type)
38913505cb9fSJiri Olsa {
38923505cb9fSJiri Olsa 	enum bpf_prog_type ptype;
38933505cb9fSJiri Olsa 
38943505cb9fSJiri Olsa 	switch (prog->type) {
38953505cb9fSJiri Olsa 	case BPF_PROG_TYPE_CGROUP_SOCK:
38963505cb9fSJiri Olsa 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
38973505cb9fSJiri Olsa 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
38983505cb9fSJiri Olsa 	case BPF_PROG_TYPE_SK_LOOKUP:
38993505cb9fSJiri Olsa 		return attach_type == prog->expected_attach_type ? 0 : -EINVAL;
39003505cb9fSJiri Olsa 	case BPF_PROG_TYPE_CGROUP_SKB:
3901caf8f28eSAndrii Nakryiko 		if (!bpf_token_capable(prog->aux->token, CAP_NET_ADMIN))
39023505cb9fSJiri Olsa 			/* cg-skb progs can be loaded by unpriv user.
39033505cb9fSJiri Olsa 			 * check permissions at attach time.
39043505cb9fSJiri Olsa 			 */
39053505cb9fSJiri Olsa 			return -EPERM;
39063505cb9fSJiri Olsa 		return prog->enforce_expected_attach_type &&
39073505cb9fSJiri Olsa 			prog->expected_attach_type != attach_type ?
39083505cb9fSJiri Olsa 			-EINVAL : 0;
39093505cb9fSJiri Olsa 	case BPF_PROG_TYPE_EXT:
39103505cb9fSJiri Olsa 		return 0;
39113505cb9fSJiri Olsa 	case BPF_PROG_TYPE_NETFILTER:
39123505cb9fSJiri Olsa 		if (attach_type != BPF_NETFILTER)
39133505cb9fSJiri Olsa 			return -EINVAL;
39143505cb9fSJiri Olsa 		return 0;
39153505cb9fSJiri Olsa 	case BPF_PROG_TYPE_PERF_EVENT:
39163505cb9fSJiri Olsa 	case BPF_PROG_TYPE_TRACEPOINT:
39173505cb9fSJiri Olsa 		if (attach_type != BPF_PERF_EVENT)
39183505cb9fSJiri Olsa 			return -EINVAL;
39193505cb9fSJiri Olsa 		return 0;
39203505cb9fSJiri Olsa 	case BPF_PROG_TYPE_KPROBE:
39213505cb9fSJiri Olsa 		if (prog->expected_attach_type == BPF_TRACE_KPROBE_MULTI &&
39223505cb9fSJiri Olsa 		    attach_type != BPF_TRACE_KPROBE_MULTI)
39233505cb9fSJiri Olsa 			return -EINVAL;
392489ae89f5SJiri Olsa 		if (prog->expected_attach_type == BPF_TRACE_UPROBE_MULTI &&
392589ae89f5SJiri Olsa 		    attach_type != BPF_TRACE_UPROBE_MULTI)
392689ae89f5SJiri Olsa 			return -EINVAL;
39273505cb9fSJiri Olsa 		if (attach_type != BPF_PERF_EVENT &&
392889ae89f5SJiri Olsa 		    attach_type != BPF_TRACE_KPROBE_MULTI &&
392989ae89f5SJiri Olsa 		    attach_type != BPF_TRACE_UPROBE_MULTI)
39303505cb9fSJiri Olsa 			return -EINVAL;
39313505cb9fSJiri Olsa 		return 0;
39323505cb9fSJiri Olsa 	case BPF_PROG_TYPE_SCHED_CLS:
39333505cb9fSJiri Olsa 		if (attach_type != BPF_TCX_INGRESS &&
393435dfaad7SDaniel Borkmann 		    attach_type != BPF_TCX_EGRESS &&
393535dfaad7SDaniel Borkmann 		    attach_type != BPF_NETKIT_PRIMARY &&
393635dfaad7SDaniel Borkmann 		    attach_type != BPF_NETKIT_PEER)
39373505cb9fSJiri Olsa 			return -EINVAL;
39383505cb9fSJiri Olsa 		return 0;
39393505cb9fSJiri Olsa 	default:
39403505cb9fSJiri Olsa 		ptype = attach_type_to_prog_type(attach_type);
39413505cb9fSJiri Olsa 		if (ptype == BPF_PROG_TYPE_UNSPEC || ptype != prog->type)
39423505cb9fSJiri Olsa 			return -EINVAL;
39433505cb9fSJiri Olsa 		return 0;
39443505cb9fSJiri Olsa 	}
39453505cb9fSJiri Olsa }
39463505cb9fSJiri Olsa 
3947e420bed0SDaniel Borkmann #define BPF_PROG_ATTACH_LAST_FIELD expected_revision
3948174a79ffSJohn Fastabend 
3949e420bed0SDaniel Borkmann #define BPF_F_ATTACH_MASK_BASE	\
3950e420bed0SDaniel Borkmann 	(BPF_F_ALLOW_OVERRIDE |	\
3951e420bed0SDaniel Borkmann 	 BPF_F_ALLOW_MULTI |	\
3952e420bed0SDaniel Borkmann 	 BPF_F_REPLACE)
3953e420bed0SDaniel Borkmann 
3954e420bed0SDaniel Borkmann #define BPF_F_ATTACH_MASK_MPROG	\
3955e420bed0SDaniel Borkmann 	(BPF_F_REPLACE |	\
3956e420bed0SDaniel Borkmann 	 BPF_F_BEFORE |		\
3957e420bed0SDaniel Borkmann 	 BPF_F_AFTER |		\
3958e420bed0SDaniel Borkmann 	 BPF_F_ID |		\
3959e420bed0SDaniel Borkmann 	 BPF_F_LINK)
3960324bda9eSAlexei Starovoitov 
3961f4324551SDaniel Mack static int bpf_prog_attach(const union bpf_attr *attr)
3962f4324551SDaniel Mack {
39637f677633SAlexei Starovoitov 	enum bpf_prog_type ptype;
3964f4324551SDaniel Mack 	struct bpf_prog *prog;
39657f677633SAlexei Starovoitov 	int ret;
3966f4324551SDaniel Mack 
3967f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_ATTACH))
3968f4324551SDaniel Mack 		return -EINVAL;
3969f4324551SDaniel Mack 
3970e28784e3SAndrii Nakryiko 	ptype = attach_type_to_prog_type(attr->attach_type);
3971e28784e3SAndrii Nakryiko 	if (ptype == BPF_PROG_TYPE_UNSPEC)
3972b2cd1257SDavid Ahern 		return -EINVAL;
3973ba62d611SLorenz Bauer 	if (bpf_mprog_supported(ptype)) {
3974ba62d611SLorenz Bauer 		if (attr->attach_flags & ~BPF_F_ATTACH_MASK_MPROG)
3975e420bed0SDaniel Borkmann 			return -EINVAL;
3976ba62d611SLorenz Bauer 	} else {
3977ba62d611SLorenz Bauer 		if (attr->attach_flags & ~BPF_F_ATTACH_MASK_BASE)
3978ba62d611SLorenz Bauer 			return -EINVAL;
3979ba62d611SLorenz Bauer 		if (attr->relative_fd ||
3980ba62d611SLorenz Bauer 		    attr->expected_revision)
3981ba62d611SLorenz Bauer 			return -EINVAL;
3982ba62d611SLorenz Bauer 	}
3983b2cd1257SDavid Ahern 
3984b2cd1257SDavid Ahern 	prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
3985f4324551SDaniel Mack 	if (IS_ERR(prog))
3986f4324551SDaniel Mack 		return PTR_ERR(prog);
3987f4324551SDaniel Mack 
39885e43f899SAndrey Ignatov 	if (bpf_prog_attach_check_attach_type(prog, attr->attach_type)) {
39895e43f899SAndrey Ignatov 		bpf_prog_put(prog);
39905e43f899SAndrey Ignatov 		return -EINVAL;
39915e43f899SAndrey Ignatov 	}
39925e43f899SAndrey Ignatov 
3993fdb5c453SSean Young 	switch (ptype) {
3994fdb5c453SSean Young 	case BPF_PROG_TYPE_SK_SKB:
3995fdb5c453SSean Young 	case BPF_PROG_TYPE_SK_MSG:
3996604326b4SDaniel Borkmann 		ret = sock_map_get_from_fd(attr, prog);
3997fdb5c453SSean Young 		break;
3998fdb5c453SSean Young 	case BPF_PROG_TYPE_LIRC_MODE2:
3999fdb5c453SSean Young 		ret = lirc_prog_attach(attr, prog);
4000fdb5c453SSean Young 		break;
4001d58e468bSPetar Penkov 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
4002a3fd7ceeSJakub Sitnicki 		ret = netns_bpf_prog_attach(attr, prog);
4003d58e468bSPetar Penkov 		break;
4004e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
4005e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
4006e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
4007e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
4008e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
4009e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
4010e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
401169fd337aSStanislav Fomichev 	case BPF_PROG_TYPE_LSM:
401269fd337aSStanislav Fomichev 		if (ptype == BPF_PROG_TYPE_LSM &&
401369fd337aSStanislav Fomichev 		    prog->expected_attach_type != BPF_LSM_CGROUP)
4014e89f3edfSMilan Landaverde 			ret = -EINVAL;
4015e89f3edfSMilan Landaverde 		else
4016fdb5c453SSean Young 			ret = cgroup_bpf_prog_attach(attr, ptype, prog);
4017e28784e3SAndrii Nakryiko 		break;
4018e420bed0SDaniel Borkmann 	case BPF_PROG_TYPE_SCHED_CLS:
401935dfaad7SDaniel Borkmann 		if (attr->attach_type == BPF_TCX_INGRESS ||
402035dfaad7SDaniel Borkmann 		    attr->attach_type == BPF_TCX_EGRESS)
4021e420bed0SDaniel Borkmann 			ret = tcx_prog_attach(attr, prog);
402235dfaad7SDaniel Borkmann 		else
402335dfaad7SDaniel Borkmann 			ret = netkit_prog_attach(attr, prog);
4024e420bed0SDaniel Borkmann 		break;
4025e28784e3SAndrii Nakryiko 	default:
4026e28784e3SAndrii Nakryiko 		ret = -EINVAL;
4027f4324551SDaniel Mack 	}
4028f4324551SDaniel Mack 
40297f677633SAlexei Starovoitov 	if (ret)
40307f677633SAlexei Starovoitov 		bpf_prog_put(prog);
40317f677633SAlexei Starovoitov 	return ret;
4032f4324551SDaniel Mack }
4033f4324551SDaniel Mack 
4034e420bed0SDaniel Borkmann #define BPF_PROG_DETACH_LAST_FIELD expected_revision
4035f4324551SDaniel Mack 
4036f4324551SDaniel Mack static int bpf_prog_detach(const union bpf_attr *attr)
4037f4324551SDaniel Mack {
4038e420bed0SDaniel Borkmann 	struct bpf_prog *prog = NULL;
4039324bda9eSAlexei Starovoitov 	enum bpf_prog_type ptype;
4040e420bed0SDaniel Borkmann 	int ret;
4041f4324551SDaniel Mack 
4042f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_DETACH))
4043f4324551SDaniel Mack 		return -EINVAL;
4044f4324551SDaniel Mack 
4045e28784e3SAndrii Nakryiko 	ptype = attach_type_to_prog_type(attr->attach_type);
4046e420bed0SDaniel Borkmann 	if (bpf_mprog_supported(ptype)) {
4047e420bed0SDaniel Borkmann 		if (ptype == BPF_PROG_TYPE_UNSPEC)
4048e420bed0SDaniel Borkmann 			return -EINVAL;
4049e420bed0SDaniel Borkmann 		if (attr->attach_flags & ~BPF_F_ATTACH_MASK_MPROG)
4050e420bed0SDaniel Borkmann 			return -EINVAL;
4051e420bed0SDaniel Borkmann 		if (attr->attach_bpf_fd) {
4052e420bed0SDaniel Borkmann 			prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
4053e420bed0SDaniel Borkmann 			if (IS_ERR(prog))
4054e420bed0SDaniel Borkmann 				return PTR_ERR(prog);
4055e420bed0SDaniel Borkmann 		}
4056ba62d611SLorenz Bauer 	} else if (attr->attach_flags ||
4057ba62d611SLorenz Bauer 		   attr->relative_fd ||
4058ba62d611SLorenz Bauer 		   attr->expected_revision) {
4059ba62d611SLorenz Bauer 		return -EINVAL;
4060e420bed0SDaniel Borkmann 	}
4061e28784e3SAndrii Nakryiko 
4062e28784e3SAndrii Nakryiko 	switch (ptype) {
4063e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SK_MSG:
4064e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SK_SKB:
4065e420bed0SDaniel Borkmann 		ret = sock_map_prog_detach(attr, ptype);
4066e420bed0SDaniel Borkmann 		break;
4067e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_LIRC_MODE2:
4068e420bed0SDaniel Borkmann 		ret = lirc_prog_detach(attr);
4069e420bed0SDaniel Borkmann 		break;
4070e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
4071e420bed0SDaniel Borkmann 		ret = netns_bpf_prog_detach(attr, ptype);
4072e420bed0SDaniel Borkmann 		break;
4073e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
4074e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
4075e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
4076e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
4077e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
4078e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
4079e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
408069fd337aSStanislav Fomichev 	case BPF_PROG_TYPE_LSM:
4081e420bed0SDaniel Borkmann 		ret = cgroup_bpf_prog_detach(attr, ptype);
4082e420bed0SDaniel Borkmann 		break;
4083e420bed0SDaniel Borkmann 	case BPF_PROG_TYPE_SCHED_CLS:
408435dfaad7SDaniel Borkmann 		if (attr->attach_type == BPF_TCX_INGRESS ||
408535dfaad7SDaniel Borkmann 		    attr->attach_type == BPF_TCX_EGRESS)
4086e420bed0SDaniel Borkmann 			ret = tcx_prog_detach(attr, prog);
408735dfaad7SDaniel Borkmann 		else
408835dfaad7SDaniel Borkmann 			ret = netkit_prog_detach(attr, prog);
4089e420bed0SDaniel Borkmann 		break;
4090f4324551SDaniel Mack 	default:
4091e420bed0SDaniel Borkmann 		ret = -EINVAL;
4092f4324551SDaniel Mack 	}
409340304b2aSLawrence Brakmo 
4094e420bed0SDaniel Borkmann 	if (prog)
4095e420bed0SDaniel Borkmann 		bpf_prog_put(prog);
4096e420bed0SDaniel Borkmann 	return ret;
4097e420bed0SDaniel Borkmann }
4098e420bed0SDaniel Borkmann 
4099a4fe7838SDaniel Borkmann #define BPF_PROG_QUERY_LAST_FIELD query.revision
4100468e2f64SAlexei Starovoitov 
4101468e2f64SAlexei Starovoitov static int bpf_prog_query(const union bpf_attr *attr,
4102468e2f64SAlexei Starovoitov 			  union bpf_attr __user *uattr)
4103468e2f64SAlexei Starovoitov {
4104ed1ad5a7SAndrii Nakryiko 	if (!bpf_net_capable())
4105468e2f64SAlexei Starovoitov 		return -EPERM;
4106468e2f64SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_QUERY))
4107468e2f64SAlexei Starovoitov 		return -EINVAL;
4108468e2f64SAlexei Starovoitov 	if (attr->query.query_flags & ~BPF_F_QUERY_EFFECTIVE)
4109468e2f64SAlexei Starovoitov 		return -EINVAL;
4110468e2f64SAlexei Starovoitov 
4111468e2f64SAlexei Starovoitov 	switch (attr->query.attach_type) {
4112468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_INGRESS:
4113468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_EGRESS:
4114468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_SOCK_CREATE:
4115f5836749SStanislav Fomichev 	case BPF_CGROUP_INET_SOCK_RELEASE:
41164fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET4_BIND:
41174fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET6_BIND:
4118aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET4_POST_BIND:
4119aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET6_POST_BIND:
4120d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET4_CONNECT:
4121d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET6_CONNECT:
4122859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_CONNECT:
41231b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETPEERNAME:
41241b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETPEERNAME:
4125859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_GETPEERNAME:
41261b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETSOCKNAME:
41271b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETSOCKNAME:
4128859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_GETSOCKNAME:
41291cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP4_SENDMSG:
41301cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP6_SENDMSG:
4131859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_SENDMSG:
4132983695faSDaniel Borkmann 	case BPF_CGROUP_UDP4_RECVMSG:
4133983695faSDaniel Borkmann 	case BPF_CGROUP_UDP6_RECVMSG:
4134859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_RECVMSG:
4135468e2f64SAlexei Starovoitov 	case BPF_CGROUP_SOCK_OPS:
4136ebc614f6SRoman Gushchin 	case BPF_CGROUP_DEVICE:
41377b146cebSAndrey Ignatov 	case BPF_CGROUP_SYSCTL:
41380d01da6aSStanislav Fomichev 	case BPF_CGROUP_GETSOCKOPT:
41390d01da6aSStanislav Fomichev 	case BPF_CGROUP_SETSOCKOPT:
4140b79c9fc9SStanislav Fomichev 	case BPF_LSM_CGROUP:
4141e28784e3SAndrii Nakryiko 		return cgroup_bpf_prog_query(attr, uattr);
4142f4364dcfSSean Young 	case BPF_LIRC_MODE2:
4143f4364dcfSSean Young 		return lirc_prog_query(attr, uattr);
4144118c8e9aSStanislav Fomichev 	case BPF_FLOW_DISSECTOR:
4145e9ddbb77SJakub Sitnicki 	case BPF_SK_LOOKUP:
4146a3fd7ceeSJakub Sitnicki 		return netns_bpf_prog_query(attr, uattr);
4147748cd572SDi Zhu 	case BPF_SK_SKB_STREAM_PARSER:
4148748cd572SDi Zhu 	case BPF_SK_SKB_STREAM_VERDICT:
4149748cd572SDi Zhu 	case BPF_SK_MSG_VERDICT:
4150748cd572SDi Zhu 	case BPF_SK_SKB_VERDICT:
4151748cd572SDi Zhu 		return sock_map_bpf_prog_query(attr, uattr);
4152e420bed0SDaniel Borkmann 	case BPF_TCX_INGRESS:
4153e420bed0SDaniel Borkmann 	case BPF_TCX_EGRESS:
4154e420bed0SDaniel Borkmann 		return tcx_prog_query(attr, uattr);
415535dfaad7SDaniel Borkmann 	case BPF_NETKIT_PRIMARY:
415635dfaad7SDaniel Borkmann 	case BPF_NETKIT_PEER:
415735dfaad7SDaniel Borkmann 		return netkit_prog_query(attr, uattr);
4158468e2f64SAlexei Starovoitov 	default:
4159468e2f64SAlexei Starovoitov 		return -EINVAL;
4160468e2f64SAlexei Starovoitov 	}
4161468e2f64SAlexei Starovoitov }
4162f4324551SDaniel Mack 
4163b530e9e1SToke Høiland-Jørgensen #define BPF_PROG_TEST_RUN_LAST_FIELD test.batch_size
41641cf1cae9SAlexei Starovoitov 
41651cf1cae9SAlexei Starovoitov static int bpf_prog_test_run(const union bpf_attr *attr,
41661cf1cae9SAlexei Starovoitov 			     union bpf_attr __user *uattr)
41671cf1cae9SAlexei Starovoitov {
41681cf1cae9SAlexei Starovoitov 	struct bpf_prog *prog;
41691cf1cae9SAlexei Starovoitov 	int ret = -ENOTSUPP;
41701cf1cae9SAlexei Starovoitov 
41711cf1cae9SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_TEST_RUN))
41721cf1cae9SAlexei Starovoitov 		return -EINVAL;
41731cf1cae9SAlexei Starovoitov 
4174b0b9395dSStanislav Fomichev 	if ((attr->test.ctx_size_in && !attr->test.ctx_in) ||
4175b0b9395dSStanislav Fomichev 	    (!attr->test.ctx_size_in && attr->test.ctx_in))
4176b0b9395dSStanislav Fomichev 		return -EINVAL;
4177b0b9395dSStanislav Fomichev 
4178b0b9395dSStanislav Fomichev 	if ((attr->test.ctx_size_out && !attr->test.ctx_out) ||
4179b0b9395dSStanislav Fomichev 	    (!attr->test.ctx_size_out && attr->test.ctx_out))
4180b0b9395dSStanislav Fomichev 		return -EINVAL;
4181b0b9395dSStanislav Fomichev 
41821cf1cae9SAlexei Starovoitov 	prog = bpf_prog_get(attr->test.prog_fd);
41831cf1cae9SAlexei Starovoitov 	if (IS_ERR(prog))
41841cf1cae9SAlexei Starovoitov 		return PTR_ERR(prog);
41851cf1cae9SAlexei Starovoitov 
41861cf1cae9SAlexei Starovoitov 	if (prog->aux->ops->test_run)
41871cf1cae9SAlexei Starovoitov 		ret = prog->aux->ops->test_run(prog, attr, uattr);
41881cf1cae9SAlexei Starovoitov 
41891cf1cae9SAlexei Starovoitov 	bpf_prog_put(prog);
41901cf1cae9SAlexei Starovoitov 	return ret;
41911cf1cae9SAlexei Starovoitov }
41921cf1cae9SAlexei Starovoitov 
419334ad5580SMartin KaFai Lau #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id
419434ad5580SMartin KaFai Lau 
419534ad5580SMartin KaFai Lau static int bpf_obj_get_next_id(const union bpf_attr *attr,
419634ad5580SMartin KaFai Lau 			       union bpf_attr __user *uattr,
419734ad5580SMartin KaFai Lau 			       struct idr *idr,
419834ad5580SMartin KaFai Lau 			       spinlock_t *lock)
419934ad5580SMartin KaFai Lau {
420034ad5580SMartin KaFai Lau 	u32 next_id = attr->start_id;
420134ad5580SMartin KaFai Lau 	int err = 0;
420234ad5580SMartin KaFai Lau 
420334ad5580SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX)
420434ad5580SMartin KaFai Lau 		return -EINVAL;
420534ad5580SMartin KaFai Lau 
420634ad5580SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
420734ad5580SMartin KaFai Lau 		return -EPERM;
420834ad5580SMartin KaFai Lau 
420934ad5580SMartin KaFai Lau 	next_id++;
421034ad5580SMartin KaFai Lau 	spin_lock_bh(lock);
421134ad5580SMartin KaFai Lau 	if (!idr_get_next(idr, &next_id))
421234ad5580SMartin KaFai Lau 		err = -ENOENT;
421334ad5580SMartin KaFai Lau 	spin_unlock_bh(lock);
421434ad5580SMartin KaFai Lau 
421534ad5580SMartin KaFai Lau 	if (!err)
421634ad5580SMartin KaFai Lau 		err = put_user(next_id, &uattr->next_id);
421734ad5580SMartin KaFai Lau 
421834ad5580SMartin KaFai Lau 	return err;
421934ad5580SMartin KaFai Lau }
422034ad5580SMartin KaFai Lau 
42216086d29dSYonghong Song struct bpf_map *bpf_map_get_curr_or_next(u32 *id)
42226086d29dSYonghong Song {
42236086d29dSYonghong Song 	struct bpf_map *map;
42246086d29dSYonghong Song 
42256086d29dSYonghong Song 	spin_lock_bh(&map_idr_lock);
42266086d29dSYonghong Song again:
42276086d29dSYonghong Song 	map = idr_get_next(&map_idr, id);
42286086d29dSYonghong Song 	if (map) {
42296086d29dSYonghong Song 		map = __bpf_map_inc_not_zero(map, false);
42306086d29dSYonghong Song 		if (IS_ERR(map)) {
42316086d29dSYonghong Song 			(*id)++;
42326086d29dSYonghong Song 			goto again;
42336086d29dSYonghong Song 		}
42346086d29dSYonghong Song 	}
42356086d29dSYonghong Song 	spin_unlock_bh(&map_idr_lock);
42366086d29dSYonghong Song 
42376086d29dSYonghong Song 	return map;
42386086d29dSYonghong Song }
42396086d29dSYonghong Song 
4240a228a64fSAlexei Starovoitov struct bpf_prog *bpf_prog_get_curr_or_next(u32 *id)
4241a228a64fSAlexei Starovoitov {
4242a228a64fSAlexei Starovoitov 	struct bpf_prog *prog;
4243a228a64fSAlexei Starovoitov 
4244a228a64fSAlexei Starovoitov 	spin_lock_bh(&prog_idr_lock);
4245a228a64fSAlexei Starovoitov again:
4246a228a64fSAlexei Starovoitov 	prog = idr_get_next(&prog_idr, id);
4247a228a64fSAlexei Starovoitov 	if (prog) {
4248a228a64fSAlexei Starovoitov 		prog = bpf_prog_inc_not_zero(prog);
4249a228a64fSAlexei Starovoitov 		if (IS_ERR(prog)) {
4250a228a64fSAlexei Starovoitov 			(*id)++;
4251a228a64fSAlexei Starovoitov 			goto again;
4252a228a64fSAlexei Starovoitov 		}
4253a228a64fSAlexei Starovoitov 	}
4254a228a64fSAlexei Starovoitov 	spin_unlock_bh(&prog_idr_lock);
4255a228a64fSAlexei Starovoitov 
4256a228a64fSAlexei Starovoitov 	return prog;
4257a228a64fSAlexei Starovoitov }
4258a228a64fSAlexei Starovoitov 
4259b16d9aa4SMartin KaFai Lau #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id
4260b16d9aa4SMartin KaFai Lau 
42617e6897f9SBjörn Töpel struct bpf_prog *bpf_prog_by_id(u32 id)
42627e6897f9SBjörn Töpel {
42637e6897f9SBjörn Töpel 	struct bpf_prog *prog;
42647e6897f9SBjörn Töpel 
42657e6897f9SBjörn Töpel 	if (!id)
42667e6897f9SBjörn Töpel 		return ERR_PTR(-ENOENT);
42677e6897f9SBjörn Töpel 
42687e6897f9SBjörn Töpel 	spin_lock_bh(&prog_idr_lock);
42697e6897f9SBjörn Töpel 	prog = idr_find(&prog_idr, id);
42707e6897f9SBjörn Töpel 	if (prog)
42717e6897f9SBjörn Töpel 		prog = bpf_prog_inc_not_zero(prog);
42727e6897f9SBjörn Töpel 	else
42737e6897f9SBjörn Töpel 		prog = ERR_PTR(-ENOENT);
42747e6897f9SBjörn Töpel 	spin_unlock_bh(&prog_idr_lock);
42757e6897f9SBjörn Töpel 	return prog;
42767e6897f9SBjörn Töpel }
42777e6897f9SBjörn Töpel 
4278b16d9aa4SMartin KaFai Lau static int bpf_prog_get_fd_by_id(const union bpf_attr *attr)
4279b16d9aa4SMartin KaFai Lau {
4280b16d9aa4SMartin KaFai Lau 	struct bpf_prog *prog;
4281b16d9aa4SMartin KaFai Lau 	u32 id = attr->prog_id;
4282b16d9aa4SMartin KaFai Lau 	int fd;
4283b16d9aa4SMartin KaFai Lau 
4284b16d9aa4SMartin KaFai Lau 	if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID))
4285b16d9aa4SMartin KaFai Lau 		return -EINVAL;
4286b16d9aa4SMartin KaFai Lau 
4287b16d9aa4SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
4288b16d9aa4SMartin KaFai Lau 		return -EPERM;
4289b16d9aa4SMartin KaFai Lau 
42907e6897f9SBjörn Töpel 	prog = bpf_prog_by_id(id);
4291b16d9aa4SMartin KaFai Lau 	if (IS_ERR(prog))
4292b16d9aa4SMartin KaFai Lau 		return PTR_ERR(prog);
4293b16d9aa4SMartin KaFai Lau 
4294b16d9aa4SMartin KaFai Lau 	fd = bpf_prog_new_fd(prog);
4295b16d9aa4SMartin KaFai Lau 	if (fd < 0)
4296b16d9aa4SMartin KaFai Lau 		bpf_prog_put(prog);
4297b16d9aa4SMartin KaFai Lau 
4298b16d9aa4SMartin KaFai Lau 	return fd;
4299b16d9aa4SMartin KaFai Lau }
4300b16d9aa4SMartin KaFai Lau 
43016e71b04aSChenbo Feng #define BPF_MAP_GET_FD_BY_ID_LAST_FIELD open_flags
4302bd5f5f4eSMartin KaFai Lau 
4303bd5f5f4eSMartin KaFai Lau static int bpf_map_get_fd_by_id(const union bpf_attr *attr)
4304bd5f5f4eSMartin KaFai Lau {
4305bd5f5f4eSMartin KaFai Lau 	struct bpf_map *map;
4306bd5f5f4eSMartin KaFai Lau 	u32 id = attr->map_id;
43076e71b04aSChenbo Feng 	int f_flags;
4308bd5f5f4eSMartin KaFai Lau 	int fd;
4309bd5f5f4eSMartin KaFai Lau 
43106e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID) ||
43116e71b04aSChenbo Feng 	    attr->open_flags & ~BPF_OBJ_FLAG_MASK)
4312bd5f5f4eSMartin KaFai Lau 		return -EINVAL;
4313bd5f5f4eSMartin KaFai Lau 
4314bd5f5f4eSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
4315bd5f5f4eSMartin KaFai Lau 		return -EPERM;
4316bd5f5f4eSMartin KaFai Lau 
43176e71b04aSChenbo Feng 	f_flags = bpf_get_file_flag(attr->open_flags);
43186e71b04aSChenbo Feng 	if (f_flags < 0)
43196e71b04aSChenbo Feng 		return f_flags;
43206e71b04aSChenbo Feng 
4321bd5f5f4eSMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
4322bd5f5f4eSMartin KaFai Lau 	map = idr_find(&map_idr, id);
4323bd5f5f4eSMartin KaFai Lau 	if (map)
4324b0e4701cSStanislav Fomichev 		map = __bpf_map_inc_not_zero(map, true);
4325bd5f5f4eSMartin KaFai Lau 	else
4326bd5f5f4eSMartin KaFai Lau 		map = ERR_PTR(-ENOENT);
4327bd5f5f4eSMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
4328bd5f5f4eSMartin KaFai Lau 
4329bd5f5f4eSMartin KaFai Lau 	if (IS_ERR(map))
4330bd5f5f4eSMartin KaFai Lau 		return PTR_ERR(map);
4331bd5f5f4eSMartin KaFai Lau 
43326e71b04aSChenbo Feng 	fd = bpf_map_new_fd(map, f_flags);
4333bd5f5f4eSMartin KaFai Lau 	if (fd < 0)
4334781e6282SPeng Sun 		bpf_map_put_with_uref(map);
4335bd5f5f4eSMartin KaFai Lau 
4336bd5f5f4eSMartin KaFai Lau 	return fd;
4337bd5f5f4eSMartin KaFai Lau }
4338bd5f5f4eSMartin KaFai Lau 
43397105e828SDaniel Borkmann static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog,
4340d8eca5bbSDaniel Borkmann 					      unsigned long addr, u32 *off,
4341d8eca5bbSDaniel Borkmann 					      u32 *type)
43427105e828SDaniel Borkmann {
4343d8eca5bbSDaniel Borkmann 	const struct bpf_map *map;
43447105e828SDaniel Borkmann 	int i;
43457105e828SDaniel Borkmann 
4346984fe94fSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
4347d8eca5bbSDaniel Borkmann 	for (i = 0, *off = 0; i < prog->aux->used_map_cnt; i++) {
4348d8eca5bbSDaniel Borkmann 		map = prog->aux->used_maps[i];
4349d8eca5bbSDaniel Borkmann 		if (map == (void *)addr) {
4350d8eca5bbSDaniel Borkmann 			*type = BPF_PSEUDO_MAP_FD;
4351984fe94fSYiFei Zhu 			goto out;
4352d8eca5bbSDaniel Borkmann 		}
4353d8eca5bbSDaniel Borkmann 		if (!map->ops->map_direct_value_meta)
4354d8eca5bbSDaniel Borkmann 			continue;
4355d8eca5bbSDaniel Borkmann 		if (!map->ops->map_direct_value_meta(map, addr, off)) {
4356d8eca5bbSDaniel Borkmann 			*type = BPF_PSEUDO_MAP_VALUE;
4357984fe94fSYiFei Zhu 			goto out;
4358d8eca5bbSDaniel Borkmann 		}
4359d8eca5bbSDaniel Borkmann 	}
4360984fe94fSYiFei Zhu 	map = NULL;
4361d8eca5bbSDaniel Borkmann 
4362984fe94fSYiFei Zhu out:
4363984fe94fSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
4364984fe94fSYiFei Zhu 	return map;
43657105e828SDaniel Borkmann }
43667105e828SDaniel Borkmann 
436763960260SKees Cook static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog,
436863960260SKees Cook 					      const struct cred *f_cred)
43697105e828SDaniel Borkmann {
43707105e828SDaniel Borkmann 	const struct bpf_map *map;
43717105e828SDaniel Borkmann 	struct bpf_insn *insns;
4372d8eca5bbSDaniel Borkmann 	u32 off, type;
43737105e828SDaniel Borkmann 	u64 imm;
437429fcb05bSAndrii Nakryiko 	u8 code;
43757105e828SDaniel Borkmann 	int i;
43767105e828SDaniel Borkmann 
43777105e828SDaniel Borkmann 	insns = kmemdup(prog->insnsi, bpf_prog_insn_size(prog),
43787105e828SDaniel Borkmann 			GFP_USER);
43797105e828SDaniel Borkmann 	if (!insns)
43807105e828SDaniel Borkmann 		return insns;
43817105e828SDaniel Borkmann 
43827105e828SDaniel Borkmann 	for (i = 0; i < prog->len; i++) {
438329fcb05bSAndrii Nakryiko 		code = insns[i].code;
438429fcb05bSAndrii Nakryiko 
438529fcb05bSAndrii Nakryiko 		if (code == (BPF_JMP | BPF_TAIL_CALL)) {
43867105e828SDaniel Borkmann 			insns[i].code = BPF_JMP | BPF_CALL;
43877105e828SDaniel Borkmann 			insns[i].imm = BPF_FUNC_tail_call;
43887105e828SDaniel Borkmann 			/* fall-through */
43897105e828SDaniel Borkmann 		}
439029fcb05bSAndrii Nakryiko 		if (code == (BPF_JMP | BPF_CALL) ||
439129fcb05bSAndrii Nakryiko 		    code == (BPF_JMP | BPF_CALL_ARGS)) {
439229fcb05bSAndrii Nakryiko 			if (code == (BPF_JMP | BPF_CALL_ARGS))
43937105e828SDaniel Borkmann 				insns[i].code = BPF_JMP | BPF_CALL;
439463960260SKees Cook 			if (!bpf_dump_raw_ok(f_cred))
43957105e828SDaniel Borkmann 				insns[i].imm = 0;
43967105e828SDaniel Borkmann 			continue;
43977105e828SDaniel Borkmann 		}
439829fcb05bSAndrii Nakryiko 		if (BPF_CLASS(code) == BPF_LDX && BPF_MODE(code) == BPF_PROBE_MEM) {
439929fcb05bSAndrii Nakryiko 			insns[i].code = BPF_LDX | BPF_SIZE(code) | BPF_MEM;
440029fcb05bSAndrii Nakryiko 			continue;
440129fcb05bSAndrii Nakryiko 		}
44027105e828SDaniel Borkmann 
440329fcb05bSAndrii Nakryiko 		if (code != (BPF_LD | BPF_IMM | BPF_DW))
44047105e828SDaniel Borkmann 			continue;
44057105e828SDaniel Borkmann 
44067105e828SDaniel Borkmann 		imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm;
4407d8eca5bbSDaniel Borkmann 		map = bpf_map_from_imm(prog, imm, &off, &type);
44087105e828SDaniel Borkmann 		if (map) {
4409d8eca5bbSDaniel Borkmann 			insns[i].src_reg = type;
44107105e828SDaniel Borkmann 			insns[i].imm = map->id;
4411d8eca5bbSDaniel Borkmann 			insns[i + 1].imm = off;
44127105e828SDaniel Borkmann 			continue;
44137105e828SDaniel Borkmann 		}
44147105e828SDaniel Borkmann 	}
44157105e828SDaniel Borkmann 
44167105e828SDaniel Borkmann 	return insns;
44177105e828SDaniel Borkmann }
44187105e828SDaniel Borkmann 
4419c454a46bSMartin KaFai Lau static int set_info_rec_size(struct bpf_prog_info *info)
4420c454a46bSMartin KaFai Lau {
4421c454a46bSMartin KaFai Lau 	/*
4422c454a46bSMartin KaFai Lau 	 * Ensure info.*_rec_size is the same as kernel expected size
4423c454a46bSMartin KaFai Lau 	 *
4424c454a46bSMartin KaFai Lau 	 * or
4425c454a46bSMartin KaFai Lau 	 *
4426c454a46bSMartin KaFai Lau 	 * Only allow zero *_rec_size if both _rec_size and _cnt are
4427c454a46bSMartin KaFai Lau 	 * zero.  In this case, the kernel will set the expected
4428c454a46bSMartin KaFai Lau 	 * _rec_size back to the info.
4429c454a46bSMartin KaFai Lau 	 */
4430c454a46bSMartin KaFai Lau 
443111d8b82dSYonghong Song 	if ((info->nr_func_info || info->func_info_rec_size) &&
4432c454a46bSMartin KaFai Lau 	    info->func_info_rec_size != sizeof(struct bpf_func_info))
4433c454a46bSMartin KaFai Lau 		return -EINVAL;
4434c454a46bSMartin KaFai Lau 
443511d8b82dSYonghong Song 	if ((info->nr_line_info || info->line_info_rec_size) &&
4436c454a46bSMartin KaFai Lau 	    info->line_info_rec_size != sizeof(struct bpf_line_info))
4437c454a46bSMartin KaFai Lau 		return -EINVAL;
4438c454a46bSMartin KaFai Lau 
443911d8b82dSYonghong Song 	if ((info->nr_jited_line_info || info->jited_line_info_rec_size) &&
4440c454a46bSMartin KaFai Lau 	    info->jited_line_info_rec_size != sizeof(__u64))
4441c454a46bSMartin KaFai Lau 		return -EINVAL;
4442c454a46bSMartin KaFai Lau 
4443c454a46bSMartin KaFai Lau 	info->func_info_rec_size = sizeof(struct bpf_func_info);
4444c454a46bSMartin KaFai Lau 	info->line_info_rec_size = sizeof(struct bpf_line_info);
4445c454a46bSMartin KaFai Lau 	info->jited_line_info_rec_size = sizeof(__u64);
4446c454a46bSMartin KaFai Lau 
4447c454a46bSMartin KaFai Lau 	return 0;
4448c454a46bSMartin KaFai Lau }
4449c454a46bSMartin KaFai Lau 
445063960260SKees Cook static int bpf_prog_get_info_by_fd(struct file *file,
445163960260SKees Cook 				   struct bpf_prog *prog,
44521e270976SMartin KaFai Lau 				   const union bpf_attr *attr,
44531e270976SMartin KaFai Lau 				   union bpf_attr __user *uattr)
44541e270976SMartin KaFai Lau {
44551e270976SMartin KaFai Lau 	struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info);
44566644aabbSStanislav Fomichev 	struct btf *attach_btf = bpf_prog_get_target_btf(prog);
44575c6f2588SGreg Kroah-Hartman 	struct bpf_prog_info info;
44581e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
445961a0abaeSEric Dumazet 	struct bpf_prog_kstats stats;
44601e270976SMartin KaFai Lau 	char __user *uinsns;
44611e270976SMartin KaFai Lau 	u32 ulen;
44621e270976SMartin KaFai Lau 	int err;
44631e270976SMartin KaFai Lau 
4464af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len);
44651e270976SMartin KaFai Lau 	if (err)
44661e270976SMartin KaFai Lau 		return err;
44671e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
44681e270976SMartin KaFai Lau 
44695c6f2588SGreg Kroah-Hartman 	memset(&info, 0, sizeof(info));
44701e270976SMartin KaFai Lau 	if (copy_from_user(&info, uinfo, info_len))
447189b09689SDaniel Borkmann 		return -EFAULT;
44721e270976SMartin KaFai Lau 
44731e270976SMartin KaFai Lau 	info.type = prog->type;
44741e270976SMartin KaFai Lau 	info.id = prog->aux->id;
4475cb4d2b3fSMartin KaFai Lau 	info.load_time = prog->aux->load_time;
4476cb4d2b3fSMartin KaFai Lau 	info.created_by_uid = from_kuid_munged(current_user_ns(),
4477cb4d2b3fSMartin KaFai Lau 					       prog->aux->user->uid);
4478b85fab0eSJiri Olsa 	info.gpl_compatible = prog->gpl_compatible;
44791e270976SMartin KaFai Lau 
44801e270976SMartin KaFai Lau 	memcpy(info.tag, prog->tag, sizeof(prog->tag));
4481cb4d2b3fSMartin KaFai Lau 	memcpy(info.name, prog->aux->name, sizeof(prog->aux->name));
4482cb4d2b3fSMartin KaFai Lau 
4483984fe94fSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
4484cb4d2b3fSMartin KaFai Lau 	ulen = info.nr_map_ids;
4485cb4d2b3fSMartin KaFai Lau 	info.nr_map_ids = prog->aux->used_map_cnt;
4486cb4d2b3fSMartin KaFai Lau 	ulen = min_t(u32, info.nr_map_ids, ulen);
4487cb4d2b3fSMartin KaFai Lau 	if (ulen) {
4488721e08daSMartin KaFai Lau 		u32 __user *user_map_ids = u64_to_user_ptr(info.map_ids);
4489cb4d2b3fSMartin KaFai Lau 		u32 i;
4490cb4d2b3fSMartin KaFai Lau 
4491cb4d2b3fSMartin KaFai Lau 		for (i = 0; i < ulen; i++)
4492cb4d2b3fSMartin KaFai Lau 			if (put_user(prog->aux->used_maps[i]->id,
4493984fe94fSYiFei Zhu 				     &user_map_ids[i])) {
4494984fe94fSYiFei Zhu 				mutex_unlock(&prog->aux->used_maps_mutex);
4495cb4d2b3fSMartin KaFai Lau 				return -EFAULT;
4496cb4d2b3fSMartin KaFai Lau 			}
4497984fe94fSYiFei Zhu 	}
4498984fe94fSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
44991e270976SMartin KaFai Lau 
4500c454a46bSMartin KaFai Lau 	err = set_info_rec_size(&info);
4501c454a46bSMartin KaFai Lau 	if (err)
4502c454a46bSMartin KaFai Lau 		return err;
45037337224fSMartin KaFai Lau 
45045f8f8b93SAlexei Starovoitov 	bpf_prog_get_stats(prog, &stats);
45055f8f8b93SAlexei Starovoitov 	info.run_time_ns = stats.nsecs;
45065f8f8b93SAlexei Starovoitov 	info.run_cnt = stats.cnt;
45079ed9e9baSAlexei Starovoitov 	info.recursion_misses = stats.misses;
45085f8f8b93SAlexei Starovoitov 
4509aba64c7dSDave Marchevsky 	info.verified_insns = prog->aux->verified_insns;
4510aba64c7dSDave Marchevsky 
45112c78ee89SAlexei Starovoitov 	if (!bpf_capable()) {
45121e270976SMartin KaFai Lau 		info.jited_prog_len = 0;
45131e270976SMartin KaFai Lau 		info.xlated_prog_len = 0;
4514dbecd738SSandipan Das 		info.nr_jited_ksyms = 0;
451528c2fae7SDaniel Borkmann 		info.nr_jited_func_lens = 0;
451611d8b82dSYonghong Song 		info.nr_func_info = 0;
451711d8b82dSYonghong Song 		info.nr_line_info = 0;
451811d8b82dSYonghong Song 		info.nr_jited_line_info = 0;
45191e270976SMartin KaFai Lau 		goto done;
45201e270976SMartin KaFai Lau 	}
45211e270976SMartin KaFai Lau 
45221e270976SMartin KaFai Lau 	ulen = info.xlated_prog_len;
45239975a54bSDaniel Borkmann 	info.xlated_prog_len = bpf_prog_insn_size(prog);
45241e270976SMartin KaFai Lau 	if (info.xlated_prog_len && ulen) {
45257105e828SDaniel Borkmann 		struct bpf_insn *insns_sanitized;
45267105e828SDaniel Borkmann 		bool fault;
45277105e828SDaniel Borkmann 
452863960260SKees Cook 		if (prog->blinded && !bpf_dump_raw_ok(file->f_cred)) {
45297105e828SDaniel Borkmann 			info.xlated_prog_insns = 0;
45307105e828SDaniel Borkmann 			goto done;
45317105e828SDaniel Borkmann 		}
453263960260SKees Cook 		insns_sanitized = bpf_insn_prepare_dump(prog, file->f_cred);
45337105e828SDaniel Borkmann 		if (!insns_sanitized)
45347105e828SDaniel Borkmann 			return -ENOMEM;
45351e270976SMartin KaFai Lau 		uinsns = u64_to_user_ptr(info.xlated_prog_insns);
45361e270976SMartin KaFai Lau 		ulen = min_t(u32, info.xlated_prog_len, ulen);
45377105e828SDaniel Borkmann 		fault = copy_to_user(uinsns, insns_sanitized, ulen);
45387105e828SDaniel Borkmann 		kfree(insns_sanitized);
45397105e828SDaniel Borkmann 		if (fault)
45401e270976SMartin KaFai Lau 			return -EFAULT;
45411e270976SMartin KaFai Lau 	}
45421e270976SMartin KaFai Lau 
45439d03ebc7SStanislav Fomichev 	if (bpf_prog_is_offloaded(prog->aux)) {
4544675fc275SJakub Kicinski 		err = bpf_prog_offload_info_fill(&info, prog);
4545675fc275SJakub Kicinski 		if (err)
4546675fc275SJakub Kicinski 			return err;
4547fcfb126dSJiong Wang 		goto done;
4548fcfb126dSJiong Wang 	}
4549fcfb126dSJiong Wang 
4550fcfb126dSJiong Wang 	/* NOTE: the following code is supposed to be skipped for offload.
4551fcfb126dSJiong Wang 	 * bpf_prog_offload_info_fill() is the place to fill similar fields
4552fcfb126dSJiong Wang 	 * for offload.
4553fcfb126dSJiong Wang 	 */
4554fcfb126dSJiong Wang 	ulen = info.jited_prog_len;
45554d56a76eSSandipan Das 	if (prog->aux->func_cnt) {
45564d56a76eSSandipan Das 		u32 i;
45574d56a76eSSandipan Das 
45584d56a76eSSandipan Das 		info.jited_prog_len = 0;
45594d56a76eSSandipan Das 		for (i = 0; i < prog->aux->func_cnt; i++)
45604d56a76eSSandipan Das 			info.jited_prog_len += prog->aux->func[i]->jited_len;
45614d56a76eSSandipan Das 	} else {
4562fcfb126dSJiong Wang 		info.jited_prog_len = prog->jited_len;
45634d56a76eSSandipan Das 	}
45644d56a76eSSandipan Das 
4565fcfb126dSJiong Wang 	if (info.jited_prog_len && ulen) {
456663960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
4567fcfb126dSJiong Wang 			uinsns = u64_to_user_ptr(info.jited_prog_insns);
4568fcfb126dSJiong Wang 			ulen = min_t(u32, info.jited_prog_len, ulen);
45694d56a76eSSandipan Das 
45704d56a76eSSandipan Das 			/* for multi-function programs, copy the JITed
45714d56a76eSSandipan Das 			 * instructions for all the functions
45724d56a76eSSandipan Das 			 */
45734d56a76eSSandipan Das 			if (prog->aux->func_cnt) {
45744d56a76eSSandipan Das 				u32 len, free, i;
45754d56a76eSSandipan Das 				u8 *img;
45764d56a76eSSandipan Das 
45774d56a76eSSandipan Das 				free = ulen;
45784d56a76eSSandipan Das 				for (i = 0; i < prog->aux->func_cnt; i++) {
45794d56a76eSSandipan Das 					len = prog->aux->func[i]->jited_len;
45804d56a76eSSandipan Das 					len = min_t(u32, len, free);
45814d56a76eSSandipan Das 					img = (u8 *) prog->aux->func[i]->bpf_func;
45824d56a76eSSandipan Das 					if (copy_to_user(uinsns, img, len))
45834d56a76eSSandipan Das 						return -EFAULT;
45844d56a76eSSandipan Das 					uinsns += len;
45854d56a76eSSandipan Das 					free -= len;
45864d56a76eSSandipan Das 					if (!free)
45874d56a76eSSandipan Das 						break;
45884d56a76eSSandipan Das 				}
45894d56a76eSSandipan Das 			} else {
4590fcfb126dSJiong Wang 				if (copy_to_user(uinsns, prog->bpf_func, ulen))
4591fcfb126dSJiong Wang 					return -EFAULT;
45924d56a76eSSandipan Das 			}
4593fcfb126dSJiong Wang 		} else {
4594fcfb126dSJiong Wang 			info.jited_prog_insns = 0;
4595fcfb126dSJiong Wang 		}
4596675fc275SJakub Kicinski 	}
4597675fc275SJakub Kicinski 
4598dbecd738SSandipan Das 	ulen = info.nr_jited_ksyms;
4599ff1889fcSSong Liu 	info.nr_jited_ksyms = prog->aux->func_cnt ? : 1;
46007a5725ddSSong Liu 	if (ulen) {
460163960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
4602ff1889fcSSong Liu 			unsigned long ksym_addr;
4603dbecd738SSandipan Das 			u64 __user *user_ksyms;
4604dbecd738SSandipan Das 			u32 i;
4605dbecd738SSandipan Das 
4606dbecd738SSandipan Das 			/* copy the address of the kernel symbol
4607dbecd738SSandipan Das 			 * corresponding to each function
4608dbecd738SSandipan Das 			 */
4609dbecd738SSandipan Das 			ulen = min_t(u32, info.nr_jited_ksyms, ulen);
4610dbecd738SSandipan Das 			user_ksyms = u64_to_user_ptr(info.jited_ksyms);
4611ff1889fcSSong Liu 			if (prog->aux->func_cnt) {
4612dbecd738SSandipan Das 				for (i = 0; i < ulen; i++) {
4613ff1889fcSSong Liu 					ksym_addr = (unsigned long)
4614ff1889fcSSong Liu 						prog->aux->func[i]->bpf_func;
4615ff1889fcSSong Liu 					if (put_user((u64) ksym_addr,
4616ff1889fcSSong Liu 						     &user_ksyms[i]))
4617ff1889fcSSong Liu 						return -EFAULT;
4618ff1889fcSSong Liu 				}
4619ff1889fcSSong Liu 			} else {
4620ff1889fcSSong Liu 				ksym_addr = (unsigned long) prog->bpf_func;
4621ff1889fcSSong Liu 				if (put_user((u64) ksym_addr, &user_ksyms[0]))
4622dbecd738SSandipan Das 					return -EFAULT;
4623dbecd738SSandipan Das 			}
4624dbecd738SSandipan Das 		} else {
4625dbecd738SSandipan Das 			info.jited_ksyms = 0;
4626dbecd738SSandipan Das 		}
4627dbecd738SSandipan Das 	}
4628dbecd738SSandipan Das 
4629815581c1SSandipan Das 	ulen = info.nr_jited_func_lens;
4630ff1889fcSSong Liu 	info.nr_jited_func_lens = prog->aux->func_cnt ? : 1;
46317a5725ddSSong Liu 	if (ulen) {
463263960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
4633815581c1SSandipan Das 			u32 __user *user_lens;
4634815581c1SSandipan Das 			u32 func_len, i;
4635815581c1SSandipan Das 
4636815581c1SSandipan Das 			/* copy the JITed image lengths for each function */
4637815581c1SSandipan Das 			ulen = min_t(u32, info.nr_jited_func_lens, ulen);
4638815581c1SSandipan Das 			user_lens = u64_to_user_ptr(info.jited_func_lens);
4639ff1889fcSSong Liu 			if (prog->aux->func_cnt) {
4640815581c1SSandipan Das 				for (i = 0; i < ulen; i++) {
4641ff1889fcSSong Liu 					func_len =
4642ff1889fcSSong Liu 						prog->aux->func[i]->jited_len;
4643815581c1SSandipan Das 					if (put_user(func_len, &user_lens[i]))
4644815581c1SSandipan Das 						return -EFAULT;
4645815581c1SSandipan Das 				}
4646815581c1SSandipan Das 			} else {
4647ff1889fcSSong Liu 				func_len = prog->jited_len;
4648ff1889fcSSong Liu 				if (put_user(func_len, &user_lens[0]))
4649ff1889fcSSong Liu 					return -EFAULT;
4650ff1889fcSSong Liu 			}
4651ff1889fcSSong Liu 		} else {
4652815581c1SSandipan Das 			info.jited_func_lens = 0;
4653815581c1SSandipan Das 		}
4654815581c1SSandipan Das 	}
4655815581c1SSandipan Das 
46567337224fSMartin KaFai Lau 	if (prog->aux->btf)
465722dc4a0fSAndrii Nakryiko 		info.btf_id = btf_obj_id(prog->aux->btf);
4658b79c9fc9SStanislav Fomichev 	info.attach_btf_id = prog->aux->attach_btf_id;
46596644aabbSStanislav Fomichev 	if (attach_btf)
46606644aabbSStanislav Fomichev 		info.attach_btf_obj_id = btf_obj_id(attach_btf);
4661838e9690SYonghong Song 
466211d8b82dSYonghong Song 	ulen = info.nr_func_info;
466311d8b82dSYonghong Song 	info.nr_func_info = prog->aux->func_info_cnt;
466411d8b82dSYonghong Song 	if (info.nr_func_info && ulen) {
4665838e9690SYonghong Song 		char __user *user_finfo;
4666838e9690SYonghong Song 
4667838e9690SYonghong Song 		user_finfo = u64_to_user_ptr(info.func_info);
466811d8b82dSYonghong Song 		ulen = min_t(u32, info.nr_func_info, ulen);
4669ba64e7d8SYonghong Song 		if (copy_to_user(user_finfo, prog->aux->func_info,
46707337224fSMartin KaFai Lau 				 info.func_info_rec_size * ulen))
4671838e9690SYonghong Song 			return -EFAULT;
4672838e9690SYonghong Song 	}
4673838e9690SYonghong Song 
467411d8b82dSYonghong Song 	ulen = info.nr_line_info;
467511d8b82dSYonghong Song 	info.nr_line_info = prog->aux->nr_linfo;
467611d8b82dSYonghong Song 	if (info.nr_line_info && ulen) {
4677c454a46bSMartin KaFai Lau 		__u8 __user *user_linfo;
4678c454a46bSMartin KaFai Lau 
4679c454a46bSMartin KaFai Lau 		user_linfo = u64_to_user_ptr(info.line_info);
468011d8b82dSYonghong Song 		ulen = min_t(u32, info.nr_line_info, ulen);
4681c454a46bSMartin KaFai Lau 		if (copy_to_user(user_linfo, prog->aux->linfo,
4682c454a46bSMartin KaFai Lau 				 info.line_info_rec_size * ulen))
4683c454a46bSMartin KaFai Lau 			return -EFAULT;
4684c454a46bSMartin KaFai Lau 	}
4685c454a46bSMartin KaFai Lau 
468611d8b82dSYonghong Song 	ulen = info.nr_jited_line_info;
4687c454a46bSMartin KaFai Lau 	if (prog->aux->jited_linfo)
468811d8b82dSYonghong Song 		info.nr_jited_line_info = prog->aux->nr_linfo;
4689c454a46bSMartin KaFai Lau 	else
469011d8b82dSYonghong Song 		info.nr_jited_line_info = 0;
469111d8b82dSYonghong Song 	if (info.nr_jited_line_info && ulen) {
469263960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
46932cd00852SPu Lehui 			unsigned long line_addr;
4694c454a46bSMartin KaFai Lau 			__u64 __user *user_linfo;
4695c454a46bSMartin KaFai Lau 			u32 i;
4696c454a46bSMartin KaFai Lau 
4697c454a46bSMartin KaFai Lau 			user_linfo = u64_to_user_ptr(info.jited_line_info);
469811d8b82dSYonghong Song 			ulen = min_t(u32, info.nr_jited_line_info, ulen);
4699c454a46bSMartin KaFai Lau 			for (i = 0; i < ulen; i++) {
47002cd00852SPu Lehui 				line_addr = (unsigned long)prog->aux->jited_linfo[i];
47012cd00852SPu Lehui 				if (put_user((__u64)line_addr, &user_linfo[i]))
4702c454a46bSMartin KaFai Lau 					return -EFAULT;
4703c454a46bSMartin KaFai Lau 			}
4704c454a46bSMartin KaFai Lau 		} else {
4705c454a46bSMartin KaFai Lau 			info.jited_line_info = 0;
4706c454a46bSMartin KaFai Lau 		}
4707c454a46bSMartin KaFai Lau 	}
4708c454a46bSMartin KaFai Lau 
4709c872bdb3SSong Liu 	ulen = info.nr_prog_tags;
4710c872bdb3SSong Liu 	info.nr_prog_tags = prog->aux->func_cnt ? : 1;
4711c872bdb3SSong Liu 	if (ulen) {
4712c872bdb3SSong Liu 		__u8 __user (*user_prog_tags)[BPF_TAG_SIZE];
4713c872bdb3SSong Liu 		u32 i;
4714c872bdb3SSong Liu 
4715c872bdb3SSong Liu 		user_prog_tags = u64_to_user_ptr(info.prog_tags);
4716c872bdb3SSong Liu 		ulen = min_t(u32, info.nr_prog_tags, ulen);
4717c872bdb3SSong Liu 		if (prog->aux->func_cnt) {
4718c872bdb3SSong Liu 			for (i = 0; i < ulen; i++) {
4719c872bdb3SSong Liu 				if (copy_to_user(user_prog_tags[i],
4720c872bdb3SSong Liu 						 prog->aux->func[i]->tag,
4721c872bdb3SSong Liu 						 BPF_TAG_SIZE))
4722c872bdb3SSong Liu 					return -EFAULT;
4723c872bdb3SSong Liu 			}
4724c872bdb3SSong Liu 		} else {
4725c872bdb3SSong Liu 			if (copy_to_user(user_prog_tags[0],
4726c872bdb3SSong Liu 					 prog->tag, BPF_TAG_SIZE))
4727c872bdb3SSong Liu 				return -EFAULT;
4728c872bdb3SSong Liu 		}
4729c872bdb3SSong Liu 	}
4730c872bdb3SSong Liu 
47311e270976SMartin KaFai Lau done:
47321e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
47331e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
47341e270976SMartin KaFai Lau 		return -EFAULT;
47351e270976SMartin KaFai Lau 
47361e270976SMartin KaFai Lau 	return 0;
47371e270976SMartin KaFai Lau }
47381e270976SMartin KaFai Lau 
473963960260SKees Cook static int bpf_map_get_info_by_fd(struct file *file,
474063960260SKees Cook 				  struct bpf_map *map,
47411e270976SMartin KaFai Lau 				  const union bpf_attr *attr,
47421e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
47431e270976SMartin KaFai Lau {
47441e270976SMartin KaFai Lau 	struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info);
47455c6f2588SGreg Kroah-Hartman 	struct bpf_map_info info;
47461e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
47471e270976SMartin KaFai Lau 	int err;
47481e270976SMartin KaFai Lau 
4749af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len);
47501e270976SMartin KaFai Lau 	if (err)
47511e270976SMartin KaFai Lau 		return err;
47521e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
47531e270976SMartin KaFai Lau 
47545c6f2588SGreg Kroah-Hartman 	memset(&info, 0, sizeof(info));
47551e270976SMartin KaFai Lau 	info.type = map->map_type;
47561e270976SMartin KaFai Lau 	info.id = map->id;
47571e270976SMartin KaFai Lau 	info.key_size = map->key_size;
47581e270976SMartin KaFai Lau 	info.value_size = map->value_size;
47591e270976SMartin KaFai Lau 	info.max_entries = map->max_entries;
47601e270976SMartin KaFai Lau 	info.map_flags = map->map_flags;
47619330986cSJoanne Koong 	info.map_extra = map->map_extra;
4762ad5b177bSMartin KaFai Lau 	memcpy(info.name, map->name, sizeof(map->name));
47631e270976SMartin KaFai Lau 
476478958fcaSMartin KaFai Lau 	if (map->btf) {
476522dc4a0fSAndrii Nakryiko 		info.btf_id = btf_obj_id(map->btf);
47669b2cf328SMartin KaFai Lau 		info.btf_key_type_id = map->btf_key_type_id;
47679b2cf328SMartin KaFai Lau 		info.btf_value_type_id = map->btf_value_type_id;
476878958fcaSMartin KaFai Lau 	}
476985d33df3SMartin KaFai Lau 	info.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id;
47701338b933SKui-Feng Lee 	if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS)
47711338b933SKui-Feng Lee 		bpf_map_struct_ops_info_fill(&info, map);
477278958fcaSMartin KaFai Lau 
47739d03ebc7SStanislav Fomichev 	if (bpf_map_is_offloaded(map)) {
477452775b33SJakub Kicinski 		err = bpf_map_offload_info_fill(&info, map);
477552775b33SJakub Kicinski 		if (err)
477652775b33SJakub Kicinski 			return err;
477752775b33SJakub Kicinski 	}
477852775b33SJakub Kicinski 
47791e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
47801e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
47811e270976SMartin KaFai Lau 		return -EFAULT;
47821e270976SMartin KaFai Lau 
47831e270976SMartin KaFai Lau 	return 0;
47841e270976SMartin KaFai Lau }
47851e270976SMartin KaFai Lau 
478663960260SKees Cook static int bpf_btf_get_info_by_fd(struct file *file,
478763960260SKees Cook 				  struct btf *btf,
478862dab84cSMartin KaFai Lau 				  const union bpf_attr *attr,
478962dab84cSMartin KaFai Lau 				  union bpf_attr __user *uattr)
479062dab84cSMartin KaFai Lau {
479162dab84cSMartin KaFai Lau 	struct bpf_btf_info __user *uinfo = u64_to_user_ptr(attr->info.info);
479262dab84cSMartin KaFai Lau 	u32 info_len = attr->info.info_len;
479362dab84cSMartin KaFai Lau 	int err;
479462dab84cSMartin KaFai Lau 
4795af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(*uinfo), info_len);
479662dab84cSMartin KaFai Lau 	if (err)
479762dab84cSMartin KaFai Lau 		return err;
479862dab84cSMartin KaFai Lau 
479962dab84cSMartin KaFai Lau 	return btf_get_info_by_fd(btf, attr, uattr);
480062dab84cSMartin KaFai Lau }
480162dab84cSMartin KaFai Lau 
480263960260SKees Cook static int bpf_link_get_info_by_fd(struct file *file,
480363960260SKees Cook 				  struct bpf_link *link,
4804f2e10bffSAndrii Nakryiko 				  const union bpf_attr *attr,
4805f2e10bffSAndrii Nakryiko 				  union bpf_attr __user *uattr)
4806f2e10bffSAndrii Nakryiko {
4807f2e10bffSAndrii Nakryiko 	struct bpf_link_info __user *uinfo = u64_to_user_ptr(attr->info.info);
4808f2e10bffSAndrii Nakryiko 	struct bpf_link_info info;
4809f2e10bffSAndrii Nakryiko 	u32 info_len = attr->info.info_len;
4810f2e10bffSAndrii Nakryiko 	int err;
4811f2e10bffSAndrii Nakryiko 
4812af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len);
4813f2e10bffSAndrii Nakryiko 	if (err)
4814f2e10bffSAndrii Nakryiko 		return err;
4815f2e10bffSAndrii Nakryiko 	info_len = min_t(u32, sizeof(info), info_len);
4816f2e10bffSAndrii Nakryiko 
4817f2e10bffSAndrii Nakryiko 	memset(&info, 0, sizeof(info));
4818f2e10bffSAndrii Nakryiko 	if (copy_from_user(&info, uinfo, info_len))
4819f2e10bffSAndrii Nakryiko 		return -EFAULT;
4820f2e10bffSAndrii Nakryiko 
4821f2e10bffSAndrii Nakryiko 	info.type = link->type;
4822f2e10bffSAndrii Nakryiko 	info.id = link->id;
482368b04864SKui-Feng Lee 	if (link->prog)
4824f2e10bffSAndrii Nakryiko 		info.prog_id = link->prog->aux->id;
4825f2e10bffSAndrii Nakryiko 
4826f2e10bffSAndrii Nakryiko 	if (link->ops->fill_link_info) {
4827f2e10bffSAndrii Nakryiko 		err = link->ops->fill_link_info(link, &info);
4828f2e10bffSAndrii Nakryiko 		if (err)
4829f2e10bffSAndrii Nakryiko 			return err;
4830f2e10bffSAndrii Nakryiko 	}
4831f2e10bffSAndrii Nakryiko 
4832f2e10bffSAndrii Nakryiko 	if (copy_to_user(uinfo, &info, info_len) ||
4833f2e10bffSAndrii Nakryiko 	    put_user(info_len, &uattr->info.info_len))
4834f2e10bffSAndrii Nakryiko 		return -EFAULT;
4835f2e10bffSAndrii Nakryiko 
4836f2e10bffSAndrii Nakryiko 	return 0;
4837f2e10bffSAndrii Nakryiko }
4838f2e10bffSAndrii Nakryiko 
4839f2e10bffSAndrii Nakryiko 
48401e270976SMartin KaFai Lau #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info
48411e270976SMartin KaFai Lau 
48421e270976SMartin KaFai Lau static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
48431e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
48441e270976SMartin KaFai Lau {
48451e270976SMartin KaFai Lau 	int ufd = attr->info.bpf_fd;
48461e270976SMartin KaFai Lau 	struct fd f;
48471e270976SMartin KaFai Lau 	int err;
48481e270976SMartin KaFai Lau 
48491e270976SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD))
48501e270976SMartin KaFai Lau 		return -EINVAL;
48511e270976SMartin KaFai Lau 
48521e270976SMartin KaFai Lau 	f = fdget(ufd);
48531e270976SMartin KaFai Lau 	if (!f.file)
48541e270976SMartin KaFai Lau 		return -EBADFD;
48551e270976SMartin KaFai Lau 
48561e270976SMartin KaFai Lau 	if (f.file->f_op == &bpf_prog_fops)
485763960260SKees Cook 		err = bpf_prog_get_info_by_fd(f.file, f.file->private_data, attr,
48581e270976SMartin KaFai Lau 					      uattr);
48591e270976SMartin KaFai Lau 	else if (f.file->f_op == &bpf_map_fops)
486063960260SKees Cook 		err = bpf_map_get_info_by_fd(f.file, f.file->private_data, attr,
48611e270976SMartin KaFai Lau 					     uattr);
486260197cfbSMartin KaFai Lau 	else if (f.file->f_op == &btf_fops)
486363960260SKees Cook 		err = bpf_btf_get_info_by_fd(f.file, f.file->private_data, attr, uattr);
4864f2e10bffSAndrii Nakryiko 	else if (f.file->f_op == &bpf_link_fops)
486563960260SKees Cook 		err = bpf_link_get_info_by_fd(f.file, f.file->private_data,
4866f2e10bffSAndrii Nakryiko 					      attr, uattr);
48671e270976SMartin KaFai Lau 	else
48681e270976SMartin KaFai Lau 		err = -EINVAL;
48691e270976SMartin KaFai Lau 
48701e270976SMartin KaFai Lau 	fdput(f);
48711e270976SMartin KaFai Lau 	return err;
48721e270976SMartin KaFai Lau }
48731e270976SMartin KaFai Lau 
48749ea7c4bfSAndrii Nakryiko #define BPF_BTF_LOAD_LAST_FIELD btf_token_fd
4875f56a653cSMartin KaFai Lau 
487647a71c1fSAndrii Nakryiko static int bpf_btf_load(const union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_size)
4877f56a653cSMartin KaFai Lau {
48789ea7c4bfSAndrii Nakryiko 	struct bpf_token *token = NULL;
48799ea7c4bfSAndrii Nakryiko 
4880f56a653cSMartin KaFai Lau 	if (CHECK_ATTR(BPF_BTF_LOAD))
4881f56a653cSMartin KaFai Lau 		return -EINVAL;
4882f56a653cSMartin KaFai Lau 
48839ea7c4bfSAndrii Nakryiko 	if (attr->btf_flags & ~BPF_F_TOKEN_FD)
48849ea7c4bfSAndrii Nakryiko 		return -EINVAL;
48859ea7c4bfSAndrii Nakryiko 
48869ea7c4bfSAndrii Nakryiko 	if (attr->btf_flags & BPF_F_TOKEN_FD) {
48879ea7c4bfSAndrii Nakryiko 		token = bpf_token_get_from_fd(attr->btf_token_fd);
48889ea7c4bfSAndrii Nakryiko 		if (IS_ERR(token))
48899ea7c4bfSAndrii Nakryiko 			return PTR_ERR(token);
48909ea7c4bfSAndrii Nakryiko 		if (!bpf_token_allow_cmd(token, BPF_BTF_LOAD)) {
48919ea7c4bfSAndrii Nakryiko 			bpf_token_put(token);
48929ea7c4bfSAndrii Nakryiko 			token = NULL;
48939ea7c4bfSAndrii Nakryiko 		}
48949ea7c4bfSAndrii Nakryiko 	}
48959ea7c4bfSAndrii Nakryiko 
48969ea7c4bfSAndrii Nakryiko 	if (!bpf_token_capable(token, CAP_BPF)) {
48979ea7c4bfSAndrii Nakryiko 		bpf_token_put(token);
4898f56a653cSMartin KaFai Lau 		return -EPERM;
48999ea7c4bfSAndrii Nakryiko 	}
49009ea7c4bfSAndrii Nakryiko 
49019ea7c4bfSAndrii Nakryiko 	bpf_token_put(token);
4902f56a653cSMartin KaFai Lau 
490347a71c1fSAndrii Nakryiko 	return btf_new_fd(attr, uattr, uattr_size);
4904f56a653cSMartin KaFai Lau }
4905f56a653cSMartin KaFai Lau 
490678958fcaSMartin KaFai Lau #define BPF_BTF_GET_FD_BY_ID_LAST_FIELD btf_id
490778958fcaSMartin KaFai Lau 
490878958fcaSMartin KaFai Lau static int bpf_btf_get_fd_by_id(const union bpf_attr *attr)
490978958fcaSMartin KaFai Lau {
491078958fcaSMartin KaFai Lau 	if (CHECK_ATTR(BPF_BTF_GET_FD_BY_ID))
491178958fcaSMartin KaFai Lau 		return -EINVAL;
491278958fcaSMartin KaFai Lau 
491378958fcaSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
491478958fcaSMartin KaFai Lau 		return -EPERM;
491578958fcaSMartin KaFai Lau 
491678958fcaSMartin KaFai Lau 	return btf_get_fd_by_id(attr->btf_id);
491778958fcaSMartin KaFai Lau }
491878958fcaSMartin KaFai Lau 
491941bdc4b4SYonghong Song static int bpf_task_fd_query_copy(const union bpf_attr *attr,
492041bdc4b4SYonghong Song 				    union bpf_attr __user *uattr,
492141bdc4b4SYonghong Song 				    u32 prog_id, u32 fd_type,
492241bdc4b4SYonghong Song 				    const char *buf, u64 probe_offset,
492341bdc4b4SYonghong Song 				    u64 probe_addr)
492441bdc4b4SYonghong Song {
492541bdc4b4SYonghong Song 	char __user *ubuf = u64_to_user_ptr(attr->task_fd_query.buf);
492641bdc4b4SYonghong Song 	u32 len = buf ? strlen(buf) : 0, input_len;
492741bdc4b4SYonghong Song 	int err = 0;
492841bdc4b4SYonghong Song 
492941bdc4b4SYonghong Song 	if (put_user(len, &uattr->task_fd_query.buf_len))
493041bdc4b4SYonghong Song 		return -EFAULT;
493141bdc4b4SYonghong Song 	input_len = attr->task_fd_query.buf_len;
493241bdc4b4SYonghong Song 	if (input_len && ubuf) {
493341bdc4b4SYonghong Song 		if (!len) {
493441bdc4b4SYonghong Song 			/* nothing to copy, just make ubuf NULL terminated */
493541bdc4b4SYonghong Song 			char zero = '\0';
493641bdc4b4SYonghong Song 
493741bdc4b4SYonghong Song 			if (put_user(zero, ubuf))
493841bdc4b4SYonghong Song 				return -EFAULT;
493941bdc4b4SYonghong Song 		} else if (input_len >= len + 1) {
494041bdc4b4SYonghong Song 			/* ubuf can hold the string with NULL terminator */
494141bdc4b4SYonghong Song 			if (copy_to_user(ubuf, buf, len + 1))
494241bdc4b4SYonghong Song 				return -EFAULT;
494341bdc4b4SYonghong Song 		} else {
494441bdc4b4SYonghong Song 			/* ubuf cannot hold the string with NULL terminator,
494541bdc4b4SYonghong Song 			 * do a partial copy with NULL terminator.
494641bdc4b4SYonghong Song 			 */
494741bdc4b4SYonghong Song 			char zero = '\0';
494841bdc4b4SYonghong Song 
494941bdc4b4SYonghong Song 			err = -ENOSPC;
495041bdc4b4SYonghong Song 			if (copy_to_user(ubuf, buf, input_len - 1))
495141bdc4b4SYonghong Song 				return -EFAULT;
495241bdc4b4SYonghong Song 			if (put_user(zero, ubuf + input_len - 1))
495341bdc4b4SYonghong Song 				return -EFAULT;
495441bdc4b4SYonghong Song 		}
495541bdc4b4SYonghong Song 	}
495641bdc4b4SYonghong Song 
495741bdc4b4SYonghong Song 	if (put_user(prog_id, &uattr->task_fd_query.prog_id) ||
495841bdc4b4SYonghong Song 	    put_user(fd_type, &uattr->task_fd_query.fd_type) ||
495941bdc4b4SYonghong Song 	    put_user(probe_offset, &uattr->task_fd_query.probe_offset) ||
496041bdc4b4SYonghong Song 	    put_user(probe_addr, &uattr->task_fd_query.probe_addr))
496141bdc4b4SYonghong Song 		return -EFAULT;
496241bdc4b4SYonghong Song 
496341bdc4b4SYonghong Song 	return err;
496441bdc4b4SYonghong Song }
496541bdc4b4SYonghong Song 
496641bdc4b4SYonghong Song #define BPF_TASK_FD_QUERY_LAST_FIELD task_fd_query.probe_addr
496741bdc4b4SYonghong Song 
496841bdc4b4SYonghong Song static int bpf_task_fd_query(const union bpf_attr *attr,
496941bdc4b4SYonghong Song 			     union bpf_attr __user *uattr)
497041bdc4b4SYonghong Song {
497141bdc4b4SYonghong Song 	pid_t pid = attr->task_fd_query.pid;
497241bdc4b4SYonghong Song 	u32 fd = attr->task_fd_query.fd;
497341bdc4b4SYonghong Song 	const struct perf_event *event;
497441bdc4b4SYonghong Song 	struct task_struct *task;
497541bdc4b4SYonghong Song 	struct file *file;
497641bdc4b4SYonghong Song 	int err;
497741bdc4b4SYonghong Song 
497841bdc4b4SYonghong Song 	if (CHECK_ATTR(BPF_TASK_FD_QUERY))
497941bdc4b4SYonghong Song 		return -EINVAL;
498041bdc4b4SYonghong Song 
498141bdc4b4SYonghong Song 	if (!capable(CAP_SYS_ADMIN))
498241bdc4b4SYonghong Song 		return -EPERM;
498341bdc4b4SYonghong Song 
498441bdc4b4SYonghong Song 	if (attr->task_fd_query.flags != 0)
498541bdc4b4SYonghong Song 		return -EINVAL;
498641bdc4b4SYonghong Song 
498783c10cc3SLee Jones 	rcu_read_lock();
498841bdc4b4SYonghong Song 	task = get_pid_task(find_vpid(pid), PIDTYPE_PID);
498983c10cc3SLee Jones 	rcu_read_unlock();
499041bdc4b4SYonghong Song 	if (!task)
499141bdc4b4SYonghong Song 		return -ENOENT;
499241bdc4b4SYonghong Song 
499341bdc4b4SYonghong Song 	err = 0;
4994b48845afSEric W. Biederman 	file = fget_task(task, fd);
4995b48845afSEric W. Biederman 	put_task_struct(task);
499641bdc4b4SYonghong Song 	if (!file)
4997b48845afSEric W. Biederman 		return -EBADF;
499841bdc4b4SYonghong Song 
499970ed506cSAndrii Nakryiko 	if (file->f_op == &bpf_link_fops) {
500070ed506cSAndrii Nakryiko 		struct bpf_link *link = file->private_data;
500170ed506cSAndrii Nakryiko 
5002a3b80e10SAndrii Nakryiko 		if (link->ops == &bpf_raw_tp_link_lops) {
500370ed506cSAndrii Nakryiko 			struct bpf_raw_tp_link *raw_tp =
500470ed506cSAndrii Nakryiko 				container_of(link, struct bpf_raw_tp_link, link);
500541bdc4b4SYonghong Song 			struct bpf_raw_event_map *btp = raw_tp->btp;
500641bdc4b4SYonghong Song 
500741bdc4b4SYonghong Song 			err = bpf_task_fd_query_copy(attr, uattr,
500870ed506cSAndrii Nakryiko 						     raw_tp->link.prog->aux->id,
500941bdc4b4SYonghong Song 						     BPF_FD_TYPE_RAW_TRACEPOINT,
501041bdc4b4SYonghong Song 						     btp->tp->name, 0, 0);
501141bdc4b4SYonghong Song 			goto put_file;
501241bdc4b4SYonghong Song 		}
501370ed506cSAndrii Nakryiko 		goto out_not_supp;
501470ed506cSAndrii Nakryiko 	}
501541bdc4b4SYonghong Song 
501641bdc4b4SYonghong Song 	event = perf_get_event(file);
501741bdc4b4SYonghong Song 	if (!IS_ERR(event)) {
501841bdc4b4SYonghong Song 		u64 probe_offset, probe_addr;
501941bdc4b4SYonghong Song 		u32 prog_id, fd_type;
502041bdc4b4SYonghong Song 		const char *buf;
502141bdc4b4SYonghong Song 
502241bdc4b4SYonghong Song 		err = bpf_get_perf_event_info(event, &prog_id, &fd_type,
502341bdc4b4SYonghong Song 					      &buf, &probe_offset,
50243acf8aceSJiri Olsa 					      &probe_addr, NULL);
502541bdc4b4SYonghong Song 		if (!err)
502641bdc4b4SYonghong Song 			err = bpf_task_fd_query_copy(attr, uattr, prog_id,
502741bdc4b4SYonghong Song 						     fd_type, buf,
502841bdc4b4SYonghong Song 						     probe_offset,
502941bdc4b4SYonghong Song 						     probe_addr);
503041bdc4b4SYonghong Song 		goto put_file;
503141bdc4b4SYonghong Song 	}
503241bdc4b4SYonghong Song 
503370ed506cSAndrii Nakryiko out_not_supp:
503441bdc4b4SYonghong Song 	err = -ENOTSUPP;
503541bdc4b4SYonghong Song put_file:
503641bdc4b4SYonghong Song 	fput(file);
503741bdc4b4SYonghong Song 	return err;
503841bdc4b4SYonghong Song }
503941bdc4b4SYonghong Song 
5040cb4d03abSBrian Vazquez #define BPF_MAP_BATCH_LAST_FIELD batch.flags
5041cb4d03abSBrian Vazquez 
50423af43ba4SHou Tao #define BPF_DO_BATCH(fn, ...)			\
5043cb4d03abSBrian Vazquez 	do {					\
5044cb4d03abSBrian Vazquez 		if (!fn) {			\
5045cb4d03abSBrian Vazquez 			err = -ENOTSUPP;	\
5046cb4d03abSBrian Vazquez 			goto err_put;		\
5047cb4d03abSBrian Vazquez 		}				\
50483af43ba4SHou Tao 		err = fn(__VA_ARGS__);		\
5049cb4d03abSBrian Vazquez 	} while (0)
5050cb4d03abSBrian Vazquez 
5051cb4d03abSBrian Vazquez static int bpf_map_do_batch(const union bpf_attr *attr,
5052cb4d03abSBrian Vazquez 			    union bpf_attr __user *uattr,
5053cb4d03abSBrian Vazquez 			    int cmd)
5054cb4d03abSBrian Vazquez {
5055353050beSDaniel Borkmann 	bool has_read  = cmd == BPF_MAP_LOOKUP_BATCH ||
5056353050beSDaniel Borkmann 			 cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH;
5057353050beSDaniel Borkmann 	bool has_write = cmd != BPF_MAP_LOOKUP_BATCH;
5058cb4d03abSBrian Vazquez 	struct bpf_map *map;
5059cb4d03abSBrian Vazquez 	int err, ufd;
5060cb4d03abSBrian Vazquez 	struct fd f;
5061cb4d03abSBrian Vazquez 
5062cb4d03abSBrian Vazquez 	if (CHECK_ATTR(BPF_MAP_BATCH))
5063cb4d03abSBrian Vazquez 		return -EINVAL;
5064cb4d03abSBrian Vazquez 
5065cb4d03abSBrian Vazquez 	ufd = attr->batch.map_fd;
5066cb4d03abSBrian Vazquez 	f = fdget(ufd);
5067cb4d03abSBrian Vazquez 	map = __bpf_map_get(f);
5068cb4d03abSBrian Vazquez 	if (IS_ERR(map))
5069cb4d03abSBrian Vazquez 		return PTR_ERR(map);
5070353050beSDaniel Borkmann 	if (has_write)
5071353050beSDaniel Borkmann 		bpf_map_write_active_inc(map);
5072353050beSDaniel Borkmann 	if (has_read && !(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
5073cb4d03abSBrian Vazquez 		err = -EPERM;
5074cb4d03abSBrian Vazquez 		goto err_put;
5075cb4d03abSBrian Vazquez 	}
5076353050beSDaniel Borkmann 	if (has_write && !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
5077cb4d03abSBrian Vazquez 		err = -EPERM;
5078cb4d03abSBrian Vazquez 		goto err_put;
5079cb4d03abSBrian Vazquez 	}
5080cb4d03abSBrian Vazquez 
5081cb4d03abSBrian Vazquez 	if (cmd == BPF_MAP_LOOKUP_BATCH)
50823af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_lookup_batch, map, attr, uattr);
508305799638SYonghong Song 	else if (cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH)
50843af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_lookup_and_delete_batch, map, attr, uattr);
5085aa2e93b8SBrian Vazquez 	else if (cmd == BPF_MAP_UPDATE_BATCH)
50863af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_update_batch, map, f.file, attr, uattr);
5087aa2e93b8SBrian Vazquez 	else
50883af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_delete_batch, map, attr, uattr);
5089cb4d03abSBrian Vazquez err_put:
509001277258SHou Tao 	if (has_write) {
509101277258SHou Tao 		maybe_wait_bpf_programs(map);
5092353050beSDaniel Borkmann 		bpf_map_write_active_dec(map);
509301277258SHou Tao 	}
5094cb4d03abSBrian Vazquez 	fdput(f);
5095cb4d03abSBrian Vazquez 	return err;
5096cb4d03abSBrian Vazquez }
5097cb4d03abSBrian Vazquez 
5098b733eeadSJiri Olsa #define BPF_LINK_CREATE_LAST_FIELD link_create.uprobe_multi.pid
5099af2ac3e1SAlexei Starovoitov static int link_create(union bpf_attr *attr, bpfptr_t uattr)
5100af6eea57SAndrii Nakryiko {
5101af6eea57SAndrii Nakryiko 	struct bpf_prog *prog;
5102af6eea57SAndrii Nakryiko 	int ret;
5103af6eea57SAndrii Nakryiko 
5104af6eea57SAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_CREATE))
5105af6eea57SAndrii Nakryiko 		return -EINVAL;
5106af6eea57SAndrii Nakryiko 
510768b04864SKui-Feng Lee 	if (attr->link_create.attach_type == BPF_STRUCT_OPS)
510868b04864SKui-Feng Lee 		return bpf_struct_ops_link_create(attr);
510968b04864SKui-Feng Lee 
51104a1e7c0cSToke Høiland-Jørgensen 	prog = bpf_prog_get(attr->link_create.prog_fd);
5111af6eea57SAndrii Nakryiko 	if (IS_ERR(prog))
5112af6eea57SAndrii Nakryiko 		return PTR_ERR(prog);
5113af6eea57SAndrii Nakryiko 
5114af6eea57SAndrii Nakryiko 	ret = bpf_prog_attach_check_attach_type(prog,
5115af6eea57SAndrii Nakryiko 						attr->link_create.attach_type);
5116af6eea57SAndrii Nakryiko 	if (ret)
51174a1e7c0cSToke Høiland-Jørgensen 		goto out;
51184a1e7c0cSToke Høiland-Jørgensen 
5119b89fbfbbSAndrii Nakryiko 	switch (prog->type) {
5120af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
5121af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
5122af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
5123af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
5124af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
5125af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
5126af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
5127af6eea57SAndrii Nakryiko 		ret = cgroup_bpf_link_attach(attr, prog);
5128af6eea57SAndrii Nakryiko 		break;
5129df86ca0dSAndrii Nakryiko 	case BPF_PROG_TYPE_EXT:
5130df86ca0dSAndrii Nakryiko 		ret = bpf_tracing_prog_attach(prog,
5131df86ca0dSAndrii Nakryiko 					      attr->link_create.target_fd,
51322fcc8241SKui-Feng Lee 					      attr->link_create.target_btf_id,
51332fcc8241SKui-Feng Lee 					      attr->link_create.tracing.cookie);
5134df86ca0dSAndrii Nakryiko 		break;
5135df86ca0dSAndrii Nakryiko 	case BPF_PROG_TYPE_LSM:
5136de4e05caSYonghong Song 	case BPF_PROG_TYPE_TRACING:
5137df86ca0dSAndrii Nakryiko 		if (attr->link_create.attach_type != prog->expected_attach_type) {
5138df86ca0dSAndrii Nakryiko 			ret = -EINVAL;
5139df86ca0dSAndrii Nakryiko 			goto out;
5140df86ca0dSAndrii Nakryiko 		}
5141df86ca0dSAndrii Nakryiko 		if (prog->expected_attach_type == BPF_TRACE_RAW_TP)
5142df86ca0dSAndrii Nakryiko 			ret = bpf_raw_tp_link_attach(prog, NULL);
5143df86ca0dSAndrii Nakryiko 		else if (prog->expected_attach_type == BPF_TRACE_ITER)
5144df86ca0dSAndrii Nakryiko 			ret = bpf_iter_link_attach(attr, uattr, prog);
514569fd337aSStanislav Fomichev 		else if (prog->expected_attach_type == BPF_LSM_CGROUP)
514669fd337aSStanislav Fomichev 			ret = cgroup_bpf_link_attach(attr, prog);
5147df86ca0dSAndrii Nakryiko 		else
5148df86ca0dSAndrii Nakryiko 			ret = bpf_tracing_prog_attach(prog,
5149df86ca0dSAndrii Nakryiko 						      attr->link_create.target_fd,
51502fcc8241SKui-Feng Lee 						      attr->link_create.target_btf_id,
51512fcc8241SKui-Feng Lee 						      attr->link_create.tracing.cookie);
5152de4e05caSYonghong Song 		break;
51537f045a49SJakub Sitnicki 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
5154e9ddbb77SJakub Sitnicki 	case BPF_PROG_TYPE_SK_LOOKUP:
51557f045a49SJakub Sitnicki 		ret = netns_bpf_link_create(attr, prog);
51567f045a49SJakub Sitnicki 		break;
5157310ad797SAndrii Nakryiko #ifdef CONFIG_NET
5158aa8d3a71SAndrii Nakryiko 	case BPF_PROG_TYPE_XDP:
5159aa8d3a71SAndrii Nakryiko 		ret = bpf_xdp_link_attach(attr, prog);
5160aa8d3a71SAndrii Nakryiko 		break;
5161e420bed0SDaniel Borkmann 	case BPF_PROG_TYPE_SCHED_CLS:
516235dfaad7SDaniel Borkmann 		if (attr->link_create.attach_type == BPF_TCX_INGRESS ||
516335dfaad7SDaniel Borkmann 		    attr->link_create.attach_type == BPF_TCX_EGRESS)
5164e420bed0SDaniel Borkmann 			ret = tcx_link_attach(attr, prog);
516535dfaad7SDaniel Borkmann 		else
516635dfaad7SDaniel Borkmann 			ret = netkit_link_attach(attr, prog);
5167e420bed0SDaniel Borkmann 		break;
516884601d6eSFlorian Westphal 	case BPF_PROG_TYPE_NETFILTER:
516984601d6eSFlorian Westphal 		ret = bpf_nf_link_attach(attr, prog);
517084601d6eSFlorian Westphal 		break;
5171310ad797SAndrii Nakryiko #endif
5172b89fbfbbSAndrii Nakryiko 	case BPF_PROG_TYPE_PERF_EVENT:
5173b89fbfbbSAndrii Nakryiko 	case BPF_PROG_TYPE_TRACEPOINT:
5174b89fbfbbSAndrii Nakryiko 		ret = bpf_perf_link_attach(attr, prog);
5175b89fbfbbSAndrii Nakryiko 		break;
51760dcac272SJiri Olsa 	case BPF_PROG_TYPE_KPROBE:
51770dcac272SJiri Olsa 		if (attr->link_create.attach_type == BPF_PERF_EVENT)
51780dcac272SJiri Olsa 			ret = bpf_perf_link_attach(attr, prog);
517989ae89f5SJiri Olsa 		else if (attr->link_create.attach_type == BPF_TRACE_KPROBE_MULTI)
51800dcac272SJiri Olsa 			ret = bpf_kprobe_multi_link_attach(attr, prog);
518189ae89f5SJiri Olsa 		else if (attr->link_create.attach_type == BPF_TRACE_UPROBE_MULTI)
518289ae89f5SJiri Olsa 			ret = bpf_uprobe_multi_link_attach(attr, prog);
51830dcac272SJiri Olsa 		break;
5184af6eea57SAndrii Nakryiko 	default:
5185af6eea57SAndrii Nakryiko 		ret = -EINVAL;
5186af6eea57SAndrii Nakryiko 	}
5187af6eea57SAndrii Nakryiko 
51884a1e7c0cSToke Høiland-Jørgensen out:
5189af6eea57SAndrii Nakryiko 	if (ret < 0)
5190af6eea57SAndrii Nakryiko 		bpf_prog_put(prog);
5191af6eea57SAndrii Nakryiko 	return ret;
5192af6eea57SAndrii Nakryiko }
5193af6eea57SAndrii Nakryiko 
5194aef56f2eSKui-Feng Lee static int link_update_map(struct bpf_link *link, union bpf_attr *attr)
5195aef56f2eSKui-Feng Lee {
5196aef56f2eSKui-Feng Lee 	struct bpf_map *new_map, *old_map = NULL;
5197aef56f2eSKui-Feng Lee 	int ret;
5198aef56f2eSKui-Feng Lee 
5199aef56f2eSKui-Feng Lee 	new_map = bpf_map_get(attr->link_update.new_map_fd);
5200aef56f2eSKui-Feng Lee 	if (IS_ERR(new_map))
520155fbae05SMartin KaFai Lau 		return PTR_ERR(new_map);
5202aef56f2eSKui-Feng Lee 
5203aef56f2eSKui-Feng Lee 	if (attr->link_update.flags & BPF_F_REPLACE) {
5204aef56f2eSKui-Feng Lee 		old_map = bpf_map_get(attr->link_update.old_map_fd);
5205aef56f2eSKui-Feng Lee 		if (IS_ERR(old_map)) {
520655fbae05SMartin KaFai Lau 			ret = PTR_ERR(old_map);
5207aef56f2eSKui-Feng Lee 			goto out_put;
5208aef56f2eSKui-Feng Lee 		}
5209aef56f2eSKui-Feng Lee 	} else if (attr->link_update.old_map_fd) {
5210aef56f2eSKui-Feng Lee 		ret = -EINVAL;
5211aef56f2eSKui-Feng Lee 		goto out_put;
5212aef56f2eSKui-Feng Lee 	}
5213aef56f2eSKui-Feng Lee 
5214aef56f2eSKui-Feng Lee 	ret = link->ops->update_map(link, new_map, old_map);
5215aef56f2eSKui-Feng Lee 
5216aef56f2eSKui-Feng Lee 	if (old_map)
5217aef56f2eSKui-Feng Lee 		bpf_map_put(old_map);
5218aef56f2eSKui-Feng Lee out_put:
5219aef56f2eSKui-Feng Lee 	bpf_map_put(new_map);
5220aef56f2eSKui-Feng Lee 	return ret;
5221aef56f2eSKui-Feng Lee }
5222aef56f2eSKui-Feng Lee 
52230c991ebcSAndrii Nakryiko #define BPF_LINK_UPDATE_LAST_FIELD link_update.old_prog_fd
52240c991ebcSAndrii Nakryiko 
52250c991ebcSAndrii Nakryiko static int link_update(union bpf_attr *attr)
52260c991ebcSAndrii Nakryiko {
52270c991ebcSAndrii Nakryiko 	struct bpf_prog *old_prog = NULL, *new_prog;
52280c991ebcSAndrii Nakryiko 	struct bpf_link *link;
52290c991ebcSAndrii Nakryiko 	u32 flags;
52300c991ebcSAndrii Nakryiko 	int ret;
52310c991ebcSAndrii Nakryiko 
52320c991ebcSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_UPDATE))
52330c991ebcSAndrii Nakryiko 		return -EINVAL;
52340c991ebcSAndrii Nakryiko 
52350c991ebcSAndrii Nakryiko 	flags = attr->link_update.flags;
52360c991ebcSAndrii Nakryiko 	if (flags & ~BPF_F_REPLACE)
52370c991ebcSAndrii Nakryiko 		return -EINVAL;
52380c991ebcSAndrii Nakryiko 
52390c991ebcSAndrii Nakryiko 	link = bpf_link_get_from_fd(attr->link_update.link_fd);
52400c991ebcSAndrii Nakryiko 	if (IS_ERR(link))
52410c991ebcSAndrii Nakryiko 		return PTR_ERR(link);
52420c991ebcSAndrii Nakryiko 
5243aef56f2eSKui-Feng Lee 	if (link->ops->update_map) {
5244aef56f2eSKui-Feng Lee 		ret = link_update_map(link, attr);
5245aef56f2eSKui-Feng Lee 		goto out_put_link;
5246aef56f2eSKui-Feng Lee 	}
5247aef56f2eSKui-Feng Lee 
52480c991ebcSAndrii Nakryiko 	new_prog = bpf_prog_get(attr->link_update.new_prog_fd);
52494adb7a4aSAndrii Nakryiko 	if (IS_ERR(new_prog)) {
52504adb7a4aSAndrii Nakryiko 		ret = PTR_ERR(new_prog);
52514adb7a4aSAndrii Nakryiko 		goto out_put_link;
52524adb7a4aSAndrii Nakryiko 	}
52530c991ebcSAndrii Nakryiko 
52540c991ebcSAndrii Nakryiko 	if (flags & BPF_F_REPLACE) {
52550c991ebcSAndrii Nakryiko 		old_prog = bpf_prog_get(attr->link_update.old_prog_fd);
52560c991ebcSAndrii Nakryiko 		if (IS_ERR(old_prog)) {
52570c991ebcSAndrii Nakryiko 			ret = PTR_ERR(old_prog);
52580c991ebcSAndrii Nakryiko 			old_prog = NULL;
52590c991ebcSAndrii Nakryiko 			goto out_put_progs;
52600c991ebcSAndrii Nakryiko 		}
52614adb7a4aSAndrii Nakryiko 	} else if (attr->link_update.old_prog_fd) {
52624adb7a4aSAndrii Nakryiko 		ret = -EINVAL;
52634adb7a4aSAndrii Nakryiko 		goto out_put_progs;
52640c991ebcSAndrii Nakryiko 	}
52650c991ebcSAndrii Nakryiko 
5266f9d04127SAndrii Nakryiko 	if (link->ops->update_prog)
5267f9d04127SAndrii Nakryiko 		ret = link->ops->update_prog(link, new_prog, old_prog);
5268f9d04127SAndrii Nakryiko 	else
52690c991ebcSAndrii Nakryiko 		ret = -EINVAL;
52700c991ebcSAndrii Nakryiko 
52710c991ebcSAndrii Nakryiko out_put_progs:
52720c991ebcSAndrii Nakryiko 	if (old_prog)
52730c991ebcSAndrii Nakryiko 		bpf_prog_put(old_prog);
52740c991ebcSAndrii Nakryiko 	if (ret)
52750c991ebcSAndrii Nakryiko 		bpf_prog_put(new_prog);
52764adb7a4aSAndrii Nakryiko out_put_link:
5277ab5d47bdSSebastian Andrzej Siewior 	bpf_link_put_direct(link);
52780c991ebcSAndrii Nakryiko 	return ret;
52790c991ebcSAndrii Nakryiko }
52800c991ebcSAndrii Nakryiko 
528173b11c2aSAndrii Nakryiko #define BPF_LINK_DETACH_LAST_FIELD link_detach.link_fd
528273b11c2aSAndrii Nakryiko 
528373b11c2aSAndrii Nakryiko static int link_detach(union bpf_attr *attr)
528473b11c2aSAndrii Nakryiko {
528573b11c2aSAndrii Nakryiko 	struct bpf_link *link;
528673b11c2aSAndrii Nakryiko 	int ret;
528773b11c2aSAndrii Nakryiko 
528873b11c2aSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_DETACH))
528973b11c2aSAndrii Nakryiko 		return -EINVAL;
529073b11c2aSAndrii Nakryiko 
529173b11c2aSAndrii Nakryiko 	link = bpf_link_get_from_fd(attr->link_detach.link_fd);
529273b11c2aSAndrii Nakryiko 	if (IS_ERR(link))
529373b11c2aSAndrii Nakryiko 		return PTR_ERR(link);
529473b11c2aSAndrii Nakryiko 
529573b11c2aSAndrii Nakryiko 	if (link->ops->detach)
529673b11c2aSAndrii Nakryiko 		ret = link->ops->detach(link);
529773b11c2aSAndrii Nakryiko 	else
529873b11c2aSAndrii Nakryiko 		ret = -EOPNOTSUPP;
529973b11c2aSAndrii Nakryiko 
5300ab5d47bdSSebastian Andrzej Siewior 	bpf_link_put_direct(link);
530173b11c2aSAndrii Nakryiko 	return ret;
530273b11c2aSAndrii Nakryiko }
530373b11c2aSAndrii Nakryiko 
5304005142b8SAlexei Starovoitov static struct bpf_link *bpf_link_inc_not_zero(struct bpf_link *link)
53052d602c8cSAndrii Nakryiko {
5306005142b8SAlexei Starovoitov 	return atomic64_fetch_add_unless(&link->refcnt, 1, 0) ? link : ERR_PTR(-ENOENT);
5307005142b8SAlexei Starovoitov }
5308005142b8SAlexei Starovoitov 
5309005142b8SAlexei Starovoitov struct bpf_link *bpf_link_by_id(u32 id)
5310005142b8SAlexei Starovoitov {
5311005142b8SAlexei Starovoitov 	struct bpf_link *link;
5312005142b8SAlexei Starovoitov 
5313005142b8SAlexei Starovoitov 	if (!id)
5314005142b8SAlexei Starovoitov 		return ERR_PTR(-ENOENT);
5315005142b8SAlexei Starovoitov 
5316005142b8SAlexei Starovoitov 	spin_lock_bh(&link_idr_lock);
5317005142b8SAlexei Starovoitov 	/* before link is "settled", ID is 0, pretend it doesn't exist yet */
5318005142b8SAlexei Starovoitov 	link = idr_find(&link_idr, id);
5319005142b8SAlexei Starovoitov 	if (link) {
5320005142b8SAlexei Starovoitov 		if (link->id)
5321005142b8SAlexei Starovoitov 			link = bpf_link_inc_not_zero(link);
5322005142b8SAlexei Starovoitov 		else
5323005142b8SAlexei Starovoitov 			link = ERR_PTR(-EAGAIN);
5324005142b8SAlexei Starovoitov 	} else {
5325005142b8SAlexei Starovoitov 		link = ERR_PTR(-ENOENT);
5326005142b8SAlexei Starovoitov 	}
5327005142b8SAlexei Starovoitov 	spin_unlock_bh(&link_idr_lock);
5328005142b8SAlexei Starovoitov 	return link;
53292d602c8cSAndrii Nakryiko }
53302d602c8cSAndrii Nakryiko 
53319f883612SDmitrii Dolgov struct bpf_link *bpf_link_get_curr_or_next(u32 *id)
53329f883612SDmitrii Dolgov {
53339f883612SDmitrii Dolgov 	struct bpf_link *link;
53349f883612SDmitrii Dolgov 
53359f883612SDmitrii Dolgov 	spin_lock_bh(&link_idr_lock);
53369f883612SDmitrii Dolgov again:
53379f883612SDmitrii Dolgov 	link = idr_get_next(&link_idr, id);
53389f883612SDmitrii Dolgov 	if (link) {
53399f883612SDmitrii Dolgov 		link = bpf_link_inc_not_zero(link);
53409f883612SDmitrii Dolgov 		if (IS_ERR(link)) {
53419f883612SDmitrii Dolgov 			(*id)++;
53429f883612SDmitrii Dolgov 			goto again;
53439f883612SDmitrii Dolgov 		}
53449f883612SDmitrii Dolgov 	}
53459f883612SDmitrii Dolgov 	spin_unlock_bh(&link_idr_lock);
53469f883612SDmitrii Dolgov 
53479f883612SDmitrii Dolgov 	return link;
53489f883612SDmitrii Dolgov }
53499f883612SDmitrii Dolgov 
53502d602c8cSAndrii Nakryiko #define BPF_LINK_GET_FD_BY_ID_LAST_FIELD link_id
53512d602c8cSAndrii Nakryiko 
53522d602c8cSAndrii Nakryiko static int bpf_link_get_fd_by_id(const union bpf_attr *attr)
53532d602c8cSAndrii Nakryiko {
53542d602c8cSAndrii Nakryiko 	struct bpf_link *link;
53552d602c8cSAndrii Nakryiko 	u32 id = attr->link_id;
5356005142b8SAlexei Starovoitov 	int fd;
53572d602c8cSAndrii Nakryiko 
53582d602c8cSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_GET_FD_BY_ID))
53592d602c8cSAndrii Nakryiko 		return -EINVAL;
53602d602c8cSAndrii Nakryiko 
53612d602c8cSAndrii Nakryiko 	if (!capable(CAP_SYS_ADMIN))
53622d602c8cSAndrii Nakryiko 		return -EPERM;
53632d602c8cSAndrii Nakryiko 
5364005142b8SAlexei Starovoitov 	link = bpf_link_by_id(id);
5365005142b8SAlexei Starovoitov 	if (IS_ERR(link))
5366005142b8SAlexei Starovoitov 		return PTR_ERR(link);
53672d602c8cSAndrii Nakryiko 
53682d602c8cSAndrii Nakryiko 	fd = bpf_link_new_fd(link);
53692d602c8cSAndrii Nakryiko 	if (fd < 0)
5370ab5d47bdSSebastian Andrzej Siewior 		bpf_link_put_direct(link);
53712d602c8cSAndrii Nakryiko 
53722d602c8cSAndrii Nakryiko 	return fd;
53732d602c8cSAndrii Nakryiko }
53742d602c8cSAndrii Nakryiko 
5375d46edd67SSong Liu DEFINE_MUTEX(bpf_stats_enabled_mutex);
5376d46edd67SSong Liu 
5377d46edd67SSong Liu static int bpf_stats_release(struct inode *inode, struct file *file)
5378d46edd67SSong Liu {
5379d46edd67SSong Liu 	mutex_lock(&bpf_stats_enabled_mutex);
5380d46edd67SSong Liu 	static_key_slow_dec(&bpf_stats_enabled_key.key);
5381d46edd67SSong Liu 	mutex_unlock(&bpf_stats_enabled_mutex);
5382d46edd67SSong Liu 	return 0;
5383d46edd67SSong Liu }
5384d46edd67SSong Liu 
5385d46edd67SSong Liu static const struct file_operations bpf_stats_fops = {
5386d46edd67SSong Liu 	.release = bpf_stats_release,
5387d46edd67SSong Liu };
5388d46edd67SSong Liu 
5389d46edd67SSong Liu static int bpf_enable_runtime_stats(void)
5390d46edd67SSong Liu {
5391d46edd67SSong Liu 	int fd;
5392d46edd67SSong Liu 
5393d46edd67SSong Liu 	mutex_lock(&bpf_stats_enabled_mutex);
5394d46edd67SSong Liu 
5395d46edd67SSong Liu 	/* Set a very high limit to avoid overflow */
5396d46edd67SSong Liu 	if (static_key_count(&bpf_stats_enabled_key.key) > INT_MAX / 2) {
5397d46edd67SSong Liu 		mutex_unlock(&bpf_stats_enabled_mutex);
5398d46edd67SSong Liu 		return -EBUSY;
5399d46edd67SSong Liu 	}
5400d46edd67SSong Liu 
5401d46edd67SSong Liu 	fd = anon_inode_getfd("bpf-stats", &bpf_stats_fops, NULL, O_CLOEXEC);
5402d46edd67SSong Liu 	if (fd >= 0)
5403d46edd67SSong Liu 		static_key_slow_inc(&bpf_stats_enabled_key.key);
5404d46edd67SSong Liu 
5405d46edd67SSong Liu 	mutex_unlock(&bpf_stats_enabled_mutex);
5406d46edd67SSong Liu 	return fd;
5407d46edd67SSong Liu }
5408d46edd67SSong Liu 
5409d46edd67SSong Liu #define BPF_ENABLE_STATS_LAST_FIELD enable_stats.type
5410d46edd67SSong Liu 
5411d46edd67SSong Liu static int bpf_enable_stats(union bpf_attr *attr)
5412d46edd67SSong Liu {
5413d46edd67SSong Liu 
5414d46edd67SSong Liu 	if (CHECK_ATTR(BPF_ENABLE_STATS))
5415d46edd67SSong Liu 		return -EINVAL;
5416d46edd67SSong Liu 
5417d46edd67SSong Liu 	if (!capable(CAP_SYS_ADMIN))
5418d46edd67SSong Liu 		return -EPERM;
5419d46edd67SSong Liu 
5420d46edd67SSong Liu 	switch (attr->enable_stats.type) {
5421d46edd67SSong Liu 	case BPF_STATS_RUN_TIME:
5422d46edd67SSong Liu 		return bpf_enable_runtime_stats();
5423d46edd67SSong Liu 	default:
5424d46edd67SSong Liu 		break;
5425d46edd67SSong Liu 	}
5426d46edd67SSong Liu 	return -EINVAL;
5427d46edd67SSong Liu }
5428d46edd67SSong Liu 
5429ac51d99bSYonghong Song #define BPF_ITER_CREATE_LAST_FIELD iter_create.flags
5430ac51d99bSYonghong Song 
5431ac51d99bSYonghong Song static int bpf_iter_create(union bpf_attr *attr)
5432ac51d99bSYonghong Song {
5433ac51d99bSYonghong Song 	struct bpf_link *link;
5434ac51d99bSYonghong Song 	int err;
5435ac51d99bSYonghong Song 
5436ac51d99bSYonghong Song 	if (CHECK_ATTR(BPF_ITER_CREATE))
5437ac51d99bSYonghong Song 		return -EINVAL;
5438ac51d99bSYonghong Song 
5439ac51d99bSYonghong Song 	if (attr->iter_create.flags)
5440ac51d99bSYonghong Song 		return -EINVAL;
5441ac51d99bSYonghong Song 
5442ac51d99bSYonghong Song 	link = bpf_link_get_from_fd(attr->iter_create.link_fd);
5443ac51d99bSYonghong Song 	if (IS_ERR(link))
5444ac51d99bSYonghong Song 		return PTR_ERR(link);
5445ac51d99bSYonghong Song 
5446ac51d99bSYonghong Song 	err = bpf_iter_new_fd(link);
5447ab5d47bdSSebastian Andrzej Siewior 	bpf_link_put_direct(link);
5448ac51d99bSYonghong Song 
5449ac51d99bSYonghong Song 	return err;
5450ac51d99bSYonghong Song }
5451ac51d99bSYonghong Song 
5452ef15314aSYiFei Zhu #define BPF_PROG_BIND_MAP_LAST_FIELD prog_bind_map.flags
5453ef15314aSYiFei Zhu 
5454ef15314aSYiFei Zhu static int bpf_prog_bind_map(union bpf_attr *attr)
5455ef15314aSYiFei Zhu {
5456ef15314aSYiFei Zhu 	struct bpf_prog *prog;
5457ef15314aSYiFei Zhu 	struct bpf_map *map;
5458ef15314aSYiFei Zhu 	struct bpf_map **used_maps_old, **used_maps_new;
5459ef15314aSYiFei Zhu 	int i, ret = 0;
5460ef15314aSYiFei Zhu 
5461ef15314aSYiFei Zhu 	if (CHECK_ATTR(BPF_PROG_BIND_MAP))
5462ef15314aSYiFei Zhu 		return -EINVAL;
5463ef15314aSYiFei Zhu 
5464ef15314aSYiFei Zhu 	if (attr->prog_bind_map.flags)
5465ef15314aSYiFei Zhu 		return -EINVAL;
5466ef15314aSYiFei Zhu 
5467ef15314aSYiFei Zhu 	prog = bpf_prog_get(attr->prog_bind_map.prog_fd);
5468ef15314aSYiFei Zhu 	if (IS_ERR(prog))
5469ef15314aSYiFei Zhu 		return PTR_ERR(prog);
5470ef15314aSYiFei Zhu 
5471ef15314aSYiFei Zhu 	map = bpf_map_get(attr->prog_bind_map.map_fd);
5472ef15314aSYiFei Zhu 	if (IS_ERR(map)) {
5473ef15314aSYiFei Zhu 		ret = PTR_ERR(map);
5474ef15314aSYiFei Zhu 		goto out_prog_put;
5475ef15314aSYiFei Zhu 	}
5476ef15314aSYiFei Zhu 
5477ef15314aSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
5478ef15314aSYiFei Zhu 
5479ef15314aSYiFei Zhu 	used_maps_old = prog->aux->used_maps;
5480ef15314aSYiFei Zhu 
5481ef15314aSYiFei Zhu 	for (i = 0; i < prog->aux->used_map_cnt; i++)
54821028ae40SStanislav Fomichev 		if (used_maps_old[i] == map) {
54831028ae40SStanislav Fomichev 			bpf_map_put(map);
5484ef15314aSYiFei Zhu 			goto out_unlock;
54851028ae40SStanislav Fomichev 		}
5486ef15314aSYiFei Zhu 
5487ef15314aSYiFei Zhu 	used_maps_new = kmalloc_array(prog->aux->used_map_cnt + 1,
5488ef15314aSYiFei Zhu 				      sizeof(used_maps_new[0]),
5489ef15314aSYiFei Zhu 				      GFP_KERNEL);
5490ef15314aSYiFei Zhu 	if (!used_maps_new) {
5491ef15314aSYiFei Zhu 		ret = -ENOMEM;
5492ef15314aSYiFei Zhu 		goto out_unlock;
5493ef15314aSYiFei Zhu 	}
5494ef15314aSYiFei Zhu 
5495af66bfd3SHou Tao 	/* The bpf program will not access the bpf map, but for the sake of
5496af66bfd3SHou Tao 	 * simplicity, increase sleepable_refcnt for sleepable program as well.
5497af66bfd3SHou Tao 	 */
5498af66bfd3SHou Tao 	if (prog->aux->sleepable)
5499af66bfd3SHou Tao 		atomic64_inc(&map->sleepable_refcnt);
5500ef15314aSYiFei Zhu 	memcpy(used_maps_new, used_maps_old,
5501ef15314aSYiFei Zhu 	       sizeof(used_maps_old[0]) * prog->aux->used_map_cnt);
5502ef15314aSYiFei Zhu 	used_maps_new[prog->aux->used_map_cnt] = map;
5503ef15314aSYiFei Zhu 
5504ef15314aSYiFei Zhu 	prog->aux->used_map_cnt++;
5505ef15314aSYiFei Zhu 	prog->aux->used_maps = used_maps_new;
5506ef15314aSYiFei Zhu 
5507ef15314aSYiFei Zhu 	kfree(used_maps_old);
5508ef15314aSYiFei Zhu 
5509ef15314aSYiFei Zhu out_unlock:
5510ef15314aSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
5511ef15314aSYiFei Zhu 
5512ef15314aSYiFei Zhu 	if (ret)
5513ef15314aSYiFei Zhu 		bpf_map_put(map);
5514ef15314aSYiFei Zhu out_prog_put:
5515ef15314aSYiFei Zhu 	bpf_prog_put(prog);
5516ef15314aSYiFei Zhu 	return ret;
5517ef15314aSYiFei Zhu }
5518ef15314aSYiFei Zhu 
551935f96de0SAndrii Nakryiko #define BPF_TOKEN_CREATE_LAST_FIELD token_create.bpffs_fd
552035f96de0SAndrii Nakryiko 
552135f96de0SAndrii Nakryiko static int token_create(union bpf_attr *attr)
552235f96de0SAndrii Nakryiko {
552335f96de0SAndrii Nakryiko 	if (CHECK_ATTR(BPF_TOKEN_CREATE))
552435f96de0SAndrii Nakryiko 		return -EINVAL;
552535f96de0SAndrii Nakryiko 
552635f96de0SAndrii Nakryiko 	/* no flags are supported yet */
552735f96de0SAndrii Nakryiko 	if (attr->token_create.flags)
552835f96de0SAndrii Nakryiko 		return -EINVAL;
552935f96de0SAndrii Nakryiko 
553035f96de0SAndrii Nakryiko 	return bpf_token_create(attr);
553135f96de0SAndrii Nakryiko }
553235f96de0SAndrii Nakryiko 
5533af2ac3e1SAlexei Starovoitov static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size)
553499c55f7dSAlexei Starovoitov {
55358096f229SGreg Kroah-Hartman 	union bpf_attr attr;
553699c55f7dSAlexei Starovoitov 	int err;
553799c55f7dSAlexei Starovoitov 
5538dcab51f1SMartin KaFai Lau 	err = bpf_check_uarg_tail_zero(uattr, sizeof(attr), size);
553999c55f7dSAlexei Starovoitov 	if (err)
554099c55f7dSAlexei Starovoitov 		return err;
55411e270976SMartin KaFai Lau 	size = min_t(u32, size, sizeof(attr));
554299c55f7dSAlexei Starovoitov 
554399c55f7dSAlexei Starovoitov 	/* copy attributes from user space, may be less than sizeof(bpf_attr) */
55448096f229SGreg Kroah-Hartman 	memset(&attr, 0, sizeof(attr));
5545af2ac3e1SAlexei Starovoitov 	if (copy_from_bpfptr(&attr, uattr, size) != 0)
554699c55f7dSAlexei Starovoitov 		return -EFAULT;
554799c55f7dSAlexei Starovoitov 
5548afdb09c7SChenbo Feng 	err = security_bpf(cmd, &attr, size);
5549afdb09c7SChenbo Feng 	if (err < 0)
5550afdb09c7SChenbo Feng 		return err;
5551afdb09c7SChenbo Feng 
555299c55f7dSAlexei Starovoitov 	switch (cmd) {
555399c55f7dSAlexei Starovoitov 	case BPF_MAP_CREATE:
555499c55f7dSAlexei Starovoitov 		err = map_create(&attr);
555599c55f7dSAlexei Starovoitov 		break;
5556db20fd2bSAlexei Starovoitov 	case BPF_MAP_LOOKUP_ELEM:
5557db20fd2bSAlexei Starovoitov 		err = map_lookup_elem(&attr);
5558db20fd2bSAlexei Starovoitov 		break;
5559db20fd2bSAlexei Starovoitov 	case BPF_MAP_UPDATE_ELEM:
5560af2ac3e1SAlexei Starovoitov 		err = map_update_elem(&attr, uattr);
5561db20fd2bSAlexei Starovoitov 		break;
5562db20fd2bSAlexei Starovoitov 	case BPF_MAP_DELETE_ELEM:
5563b88df697SBenjamin Tissoires 		err = map_delete_elem(&attr, uattr);
5564db20fd2bSAlexei Starovoitov 		break;
5565db20fd2bSAlexei Starovoitov 	case BPF_MAP_GET_NEXT_KEY:
5566db20fd2bSAlexei Starovoitov 		err = map_get_next_key(&attr);
5567db20fd2bSAlexei Starovoitov 		break;
556887df15deSDaniel Borkmann 	case BPF_MAP_FREEZE:
556987df15deSDaniel Borkmann 		err = map_freeze(&attr);
557087df15deSDaniel Borkmann 		break;
557109756af4SAlexei Starovoitov 	case BPF_PROG_LOAD:
557247a71c1fSAndrii Nakryiko 		err = bpf_prog_load(&attr, uattr, size);
557309756af4SAlexei Starovoitov 		break;
5574b2197755SDaniel Borkmann 	case BPF_OBJ_PIN:
5575b2197755SDaniel Borkmann 		err = bpf_obj_pin(&attr);
5576b2197755SDaniel Borkmann 		break;
5577b2197755SDaniel Borkmann 	case BPF_OBJ_GET:
5578b2197755SDaniel Borkmann 		err = bpf_obj_get(&attr);
5579b2197755SDaniel Borkmann 		break;
5580f4324551SDaniel Mack 	case BPF_PROG_ATTACH:
5581f4324551SDaniel Mack 		err = bpf_prog_attach(&attr);
5582f4324551SDaniel Mack 		break;
5583f4324551SDaniel Mack 	case BPF_PROG_DETACH:
5584f4324551SDaniel Mack 		err = bpf_prog_detach(&attr);
5585f4324551SDaniel Mack 		break;
5586468e2f64SAlexei Starovoitov 	case BPF_PROG_QUERY:
5587af2ac3e1SAlexei Starovoitov 		err = bpf_prog_query(&attr, uattr.user);
5588468e2f64SAlexei Starovoitov 		break;
55891cf1cae9SAlexei Starovoitov 	case BPF_PROG_TEST_RUN:
5590af2ac3e1SAlexei Starovoitov 		err = bpf_prog_test_run(&attr, uattr.user);
55911cf1cae9SAlexei Starovoitov 		break;
559234ad5580SMartin KaFai Lau 	case BPF_PROG_GET_NEXT_ID:
5593af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
559434ad5580SMartin KaFai Lau 					  &prog_idr, &prog_idr_lock);
559534ad5580SMartin KaFai Lau 		break;
559634ad5580SMartin KaFai Lau 	case BPF_MAP_GET_NEXT_ID:
5597af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
559834ad5580SMartin KaFai Lau 					  &map_idr, &map_idr_lock);
559934ad5580SMartin KaFai Lau 		break;
56001b9ed84eSQuentin Monnet 	case BPF_BTF_GET_NEXT_ID:
5601af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
56021b9ed84eSQuentin Monnet 					  &btf_idr, &btf_idr_lock);
56031b9ed84eSQuentin Monnet 		break;
5604b16d9aa4SMartin KaFai Lau 	case BPF_PROG_GET_FD_BY_ID:
5605b16d9aa4SMartin KaFai Lau 		err = bpf_prog_get_fd_by_id(&attr);
5606b16d9aa4SMartin KaFai Lau 		break;
5607bd5f5f4eSMartin KaFai Lau 	case BPF_MAP_GET_FD_BY_ID:
5608bd5f5f4eSMartin KaFai Lau 		err = bpf_map_get_fd_by_id(&attr);
5609bd5f5f4eSMartin KaFai Lau 		break;
56101e270976SMartin KaFai Lau 	case BPF_OBJ_GET_INFO_BY_FD:
5611af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_info_by_fd(&attr, uattr.user);
56121e270976SMartin KaFai Lau 		break;
5613c4f6699dSAlexei Starovoitov 	case BPF_RAW_TRACEPOINT_OPEN:
5614c4f6699dSAlexei Starovoitov 		err = bpf_raw_tracepoint_open(&attr);
5615c4f6699dSAlexei Starovoitov 		break;
5616f56a653cSMartin KaFai Lau 	case BPF_BTF_LOAD:
561747a71c1fSAndrii Nakryiko 		err = bpf_btf_load(&attr, uattr, size);
5618f56a653cSMartin KaFai Lau 		break;
561978958fcaSMartin KaFai Lau 	case BPF_BTF_GET_FD_BY_ID:
562078958fcaSMartin KaFai Lau 		err = bpf_btf_get_fd_by_id(&attr);
562178958fcaSMartin KaFai Lau 		break;
562241bdc4b4SYonghong Song 	case BPF_TASK_FD_QUERY:
5623af2ac3e1SAlexei Starovoitov 		err = bpf_task_fd_query(&attr, uattr.user);
562441bdc4b4SYonghong Song 		break;
5625bd513cd0SMauricio Vasquez B 	case BPF_MAP_LOOKUP_AND_DELETE_ELEM:
5626bd513cd0SMauricio Vasquez B 		err = map_lookup_and_delete_elem(&attr);
5627bd513cd0SMauricio Vasquez B 		break;
5628cb4d03abSBrian Vazquez 	case BPF_MAP_LOOKUP_BATCH:
5629af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_LOOKUP_BATCH);
5630cb4d03abSBrian Vazquez 		break;
563105799638SYonghong Song 	case BPF_MAP_LOOKUP_AND_DELETE_BATCH:
5632af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user,
563305799638SYonghong Song 				       BPF_MAP_LOOKUP_AND_DELETE_BATCH);
563405799638SYonghong Song 		break;
5635aa2e93b8SBrian Vazquez 	case BPF_MAP_UPDATE_BATCH:
5636af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_UPDATE_BATCH);
5637aa2e93b8SBrian Vazquez 		break;
5638aa2e93b8SBrian Vazquez 	case BPF_MAP_DELETE_BATCH:
5639af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_DELETE_BATCH);
5640aa2e93b8SBrian Vazquez 		break;
5641af6eea57SAndrii Nakryiko 	case BPF_LINK_CREATE:
5642af2ac3e1SAlexei Starovoitov 		err = link_create(&attr, uattr);
5643af6eea57SAndrii Nakryiko 		break;
56440c991ebcSAndrii Nakryiko 	case BPF_LINK_UPDATE:
56450c991ebcSAndrii Nakryiko 		err = link_update(&attr);
56460c991ebcSAndrii Nakryiko 		break;
56472d602c8cSAndrii Nakryiko 	case BPF_LINK_GET_FD_BY_ID:
56482d602c8cSAndrii Nakryiko 		err = bpf_link_get_fd_by_id(&attr);
56492d602c8cSAndrii Nakryiko 		break;
56502d602c8cSAndrii Nakryiko 	case BPF_LINK_GET_NEXT_ID:
5651af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
56522d602c8cSAndrii Nakryiko 					  &link_idr, &link_idr_lock);
56532d602c8cSAndrii Nakryiko 		break;
5654d46edd67SSong Liu 	case BPF_ENABLE_STATS:
5655d46edd67SSong Liu 		err = bpf_enable_stats(&attr);
5656d46edd67SSong Liu 		break;
5657ac51d99bSYonghong Song 	case BPF_ITER_CREATE:
5658ac51d99bSYonghong Song 		err = bpf_iter_create(&attr);
5659ac51d99bSYonghong Song 		break;
566073b11c2aSAndrii Nakryiko 	case BPF_LINK_DETACH:
566173b11c2aSAndrii Nakryiko 		err = link_detach(&attr);
566273b11c2aSAndrii Nakryiko 		break;
5663ef15314aSYiFei Zhu 	case BPF_PROG_BIND_MAP:
5664ef15314aSYiFei Zhu 		err = bpf_prog_bind_map(&attr);
5665ef15314aSYiFei Zhu 		break;
566635f96de0SAndrii Nakryiko 	case BPF_TOKEN_CREATE:
566735f96de0SAndrii Nakryiko 		err = token_create(&attr);
566835f96de0SAndrii Nakryiko 		break;
566999c55f7dSAlexei Starovoitov 	default:
567099c55f7dSAlexei Starovoitov 		err = -EINVAL;
567199c55f7dSAlexei Starovoitov 		break;
567299c55f7dSAlexei Starovoitov 	}
567399c55f7dSAlexei Starovoitov 
567499c55f7dSAlexei Starovoitov 	return err;
567599c55f7dSAlexei Starovoitov }
567679a7f8bdSAlexei Starovoitov 
5677af2ac3e1SAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
5678af2ac3e1SAlexei Starovoitov {
5679af2ac3e1SAlexei Starovoitov 	return __sys_bpf(cmd, USER_BPFPTR(uattr), size);
5680af2ac3e1SAlexei Starovoitov }
5681af2ac3e1SAlexei Starovoitov 
568279a7f8bdSAlexei Starovoitov static bool syscall_prog_is_valid_access(int off, int size,
568379a7f8bdSAlexei Starovoitov 					 enum bpf_access_type type,
568479a7f8bdSAlexei Starovoitov 					 const struct bpf_prog *prog,
568579a7f8bdSAlexei Starovoitov 					 struct bpf_insn_access_aux *info)
568679a7f8bdSAlexei Starovoitov {
568779a7f8bdSAlexei Starovoitov 	if (off < 0 || off >= U16_MAX)
568879a7f8bdSAlexei Starovoitov 		return false;
568979a7f8bdSAlexei Starovoitov 	if (off % size != 0)
569079a7f8bdSAlexei Starovoitov 		return false;
569179a7f8bdSAlexei Starovoitov 	return true;
569279a7f8bdSAlexei Starovoitov }
569379a7f8bdSAlexei Starovoitov 
5694b1d18a75SAlexei Starovoitov BPF_CALL_3(bpf_sys_bpf, int, cmd, union bpf_attr *, attr, u32, attr_size)
569579a7f8bdSAlexei Starovoitov {
5696af2ac3e1SAlexei Starovoitov 	switch (cmd) {
5697af2ac3e1SAlexei Starovoitov 	case BPF_MAP_CREATE:
5698b88df697SBenjamin Tissoires 	case BPF_MAP_DELETE_ELEM:
5699af2ac3e1SAlexei Starovoitov 	case BPF_MAP_UPDATE_ELEM:
5700af2ac3e1SAlexei Starovoitov 	case BPF_MAP_FREEZE:
5701b88df697SBenjamin Tissoires 	case BPF_MAP_GET_FD_BY_ID:
5702af2ac3e1SAlexei Starovoitov 	case BPF_PROG_LOAD:
5703c571bd75SAlexei Starovoitov 	case BPF_BTF_LOAD:
5704b1d18a75SAlexei Starovoitov 	case BPF_LINK_CREATE:
5705b1d18a75SAlexei Starovoitov 	case BPF_RAW_TRACEPOINT_OPEN:
5706af2ac3e1SAlexei Starovoitov 		break;
570786f44fceSAlexei Starovoitov 	default:
570886f44fceSAlexei Starovoitov 		return -EINVAL;
570986f44fceSAlexei Starovoitov 	}
571086f44fceSAlexei Starovoitov 	return __sys_bpf(cmd, KERNEL_BPFPTR(attr), attr_size);
571186f44fceSAlexei Starovoitov }
571286f44fceSAlexei Starovoitov 
57134e4588f1SAlexei Starovoitov 
57144e4588f1SAlexei Starovoitov /* To shut up -Wmissing-prototypes.
57154e4588f1SAlexei Starovoitov  * This function is used by the kernel light skeleton
57164e4588f1SAlexei Starovoitov  * to load bpf programs when modules are loaded or during kernel boot.
57174e4588f1SAlexei Starovoitov  * See tools/lib/bpf/skel_internal.h
57184e4588f1SAlexei Starovoitov  */
57194e4588f1SAlexei Starovoitov int kern_sys_bpf(int cmd, union bpf_attr *attr, unsigned int size);
57204e4588f1SAlexei Starovoitov 
572186f44fceSAlexei Starovoitov int kern_sys_bpf(int cmd, union bpf_attr *attr, unsigned int size)
572286f44fceSAlexei Starovoitov {
572386f44fceSAlexei Starovoitov 	struct bpf_prog * __maybe_unused prog;
572486f44fceSAlexei Starovoitov 	struct bpf_tramp_run_ctx __maybe_unused run_ctx;
572586f44fceSAlexei Starovoitov 
572686f44fceSAlexei Starovoitov 	switch (cmd) {
5727b1d18a75SAlexei Starovoitov #ifdef CONFIG_BPF_JIT /* __bpf_prog_enter_sleepable used by trampoline and JIT */
5728b1d18a75SAlexei Starovoitov 	case BPF_PROG_TEST_RUN:
5729b1d18a75SAlexei Starovoitov 		if (attr->test.data_in || attr->test.data_out ||
5730b1d18a75SAlexei Starovoitov 		    attr->test.ctx_out || attr->test.duration ||
5731b1d18a75SAlexei Starovoitov 		    attr->test.repeat || attr->test.flags)
5732b1d18a75SAlexei Starovoitov 			return -EINVAL;
5733b1d18a75SAlexei Starovoitov 
5734b1d18a75SAlexei Starovoitov 		prog = bpf_prog_get_type(attr->test.prog_fd, BPF_PROG_TYPE_SYSCALL);
5735b1d18a75SAlexei Starovoitov 		if (IS_ERR(prog))
5736b1d18a75SAlexei Starovoitov 			return PTR_ERR(prog);
5737b1d18a75SAlexei Starovoitov 
5738b1d18a75SAlexei Starovoitov 		if (attr->test.ctx_size_in < prog->aux->max_ctx_offset ||
5739b1d18a75SAlexei Starovoitov 		    attr->test.ctx_size_in > U16_MAX) {
5740b1d18a75SAlexei Starovoitov 			bpf_prog_put(prog);
5741b1d18a75SAlexei Starovoitov 			return -EINVAL;
5742b1d18a75SAlexei Starovoitov 		}
5743b1d18a75SAlexei Starovoitov 
5744e384c7b7SKui-Feng Lee 		run_ctx.bpf_cookie = 0;
5745271de525SMartin KaFai Lau 		if (!__bpf_prog_enter_sleepable_recur(prog, &run_ctx)) {
5746b1d18a75SAlexei Starovoitov 			/* recursion detected */
57477645629fSSebastian Andrzej Siewior 			__bpf_prog_exit_sleepable_recur(prog, 0, &run_ctx);
5748b1d18a75SAlexei Starovoitov 			bpf_prog_put(prog);
5749b1d18a75SAlexei Starovoitov 			return -EBUSY;
5750b1d18a75SAlexei Starovoitov 		}
5751b1d18a75SAlexei Starovoitov 		attr->test.retval = bpf_prog_run(prog, (void *) (long) attr->test.ctx_in);
5752271de525SMartin KaFai Lau 		__bpf_prog_exit_sleepable_recur(prog, 0 /* bpf_prog_run does runtime stats */,
5753271de525SMartin KaFai Lau 						&run_ctx);
5754b1d18a75SAlexei Starovoitov 		bpf_prog_put(prog);
5755b1d18a75SAlexei Starovoitov 		return 0;
5756b1d18a75SAlexei Starovoitov #endif
5757af2ac3e1SAlexei Starovoitov 	default:
575886f44fceSAlexei Starovoitov 		return ____bpf_sys_bpf(cmd, attr, size);
575979a7f8bdSAlexei Starovoitov 	}
5760af2ac3e1SAlexei Starovoitov }
576186f44fceSAlexei Starovoitov EXPORT_SYMBOL(kern_sys_bpf);
576279a7f8bdSAlexei Starovoitov 
57633a2daa72SPu Lehui static const struct bpf_func_proto bpf_sys_bpf_proto = {
576479a7f8bdSAlexei Starovoitov 	.func		= bpf_sys_bpf,
576579a7f8bdSAlexei Starovoitov 	.gpl_only	= false,
576679a7f8bdSAlexei Starovoitov 	.ret_type	= RET_INTEGER,
576779a7f8bdSAlexei Starovoitov 	.arg1_type	= ARG_ANYTHING,
5768216e3cd2SHao Luo 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
576979a7f8bdSAlexei Starovoitov 	.arg3_type	= ARG_CONST_SIZE,
577079a7f8bdSAlexei Starovoitov };
577179a7f8bdSAlexei Starovoitov 
577279a7f8bdSAlexei Starovoitov const struct bpf_func_proto * __weak
577379a7f8bdSAlexei Starovoitov tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
577479a7f8bdSAlexei Starovoitov {
5775*bbc1d247SAndrii Nakryiko 	return bpf_base_func_proto(func_id, prog);
577679a7f8bdSAlexei Starovoitov }
577779a7f8bdSAlexei Starovoitov 
57783abea089SAlexei Starovoitov BPF_CALL_1(bpf_sys_close, u32, fd)
57793abea089SAlexei Starovoitov {
57803abea089SAlexei Starovoitov 	/* When bpf program calls this helper there should not be
57813abea089SAlexei Starovoitov 	 * an fdget() without matching completed fdput().
57823abea089SAlexei Starovoitov 	 * This helper is allowed in the following callchain only:
57833abea089SAlexei Starovoitov 	 * sys_bpf->prog_test_run->bpf_prog->bpf_sys_close
57843abea089SAlexei Starovoitov 	 */
57853abea089SAlexei Starovoitov 	return close_fd(fd);
57863abea089SAlexei Starovoitov }
57873abea089SAlexei Starovoitov 
57883a2daa72SPu Lehui static const struct bpf_func_proto bpf_sys_close_proto = {
57893abea089SAlexei Starovoitov 	.func		= bpf_sys_close,
57903abea089SAlexei Starovoitov 	.gpl_only	= false,
57913abea089SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
57923abea089SAlexei Starovoitov 	.arg1_type	= ARG_ANYTHING,
57933abea089SAlexei Starovoitov };
57943abea089SAlexei Starovoitov 
5795d6aef08aSKumar Kartikeya Dwivedi BPF_CALL_4(bpf_kallsyms_lookup_name, const char *, name, int, name_sz, int, flags, u64 *, res)
5796d6aef08aSKumar Kartikeya Dwivedi {
5797d6aef08aSKumar Kartikeya Dwivedi 	if (flags)
5798d6aef08aSKumar Kartikeya Dwivedi 		return -EINVAL;
5799d6aef08aSKumar Kartikeya Dwivedi 
5800d6aef08aSKumar Kartikeya Dwivedi 	if (name_sz <= 1 || name[name_sz - 1])
5801d6aef08aSKumar Kartikeya Dwivedi 		return -EINVAL;
5802d6aef08aSKumar Kartikeya Dwivedi 
5803d6aef08aSKumar Kartikeya Dwivedi 	if (!bpf_dump_raw_ok(current_cred()))
5804d6aef08aSKumar Kartikeya Dwivedi 		return -EPERM;
5805d6aef08aSKumar Kartikeya Dwivedi 
5806d6aef08aSKumar Kartikeya Dwivedi 	*res = kallsyms_lookup_name(name);
5807d6aef08aSKumar Kartikeya Dwivedi 	return *res ? 0 : -ENOENT;
5808d6aef08aSKumar Kartikeya Dwivedi }
5809d6aef08aSKumar Kartikeya Dwivedi 
5810dc368e1cSJoanne Koong static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
5811d6aef08aSKumar Kartikeya Dwivedi 	.func		= bpf_kallsyms_lookup_name,
5812d6aef08aSKumar Kartikeya Dwivedi 	.gpl_only	= false,
5813d6aef08aSKumar Kartikeya Dwivedi 	.ret_type	= RET_INTEGER,
5814d6aef08aSKumar Kartikeya Dwivedi 	.arg1_type	= ARG_PTR_TO_MEM,
5815d4efb170SKumar Kartikeya Dwivedi 	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
5816d6aef08aSKumar Kartikeya Dwivedi 	.arg3_type	= ARG_ANYTHING,
5817d6aef08aSKumar Kartikeya Dwivedi 	.arg4_type	= ARG_PTR_TO_LONG,
5818d6aef08aSKumar Kartikeya Dwivedi };
5819d6aef08aSKumar Kartikeya Dwivedi 
582079a7f8bdSAlexei Starovoitov static const struct bpf_func_proto *
582179a7f8bdSAlexei Starovoitov syscall_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
582279a7f8bdSAlexei Starovoitov {
582379a7f8bdSAlexei Starovoitov 	switch (func_id) {
582479a7f8bdSAlexei Starovoitov 	case BPF_FUNC_sys_bpf:
5825*bbc1d247SAndrii Nakryiko 		return !bpf_token_capable(prog->aux->token, CAP_PERFMON)
5826*bbc1d247SAndrii Nakryiko 		       ? NULL : &bpf_sys_bpf_proto;
58273d78417bSAlexei Starovoitov 	case BPF_FUNC_btf_find_by_name_kind:
58283d78417bSAlexei Starovoitov 		return &bpf_btf_find_by_name_kind_proto;
58293abea089SAlexei Starovoitov 	case BPF_FUNC_sys_close:
58303abea089SAlexei Starovoitov 		return &bpf_sys_close_proto;
5831d6aef08aSKumar Kartikeya Dwivedi 	case BPF_FUNC_kallsyms_lookup_name:
5832d6aef08aSKumar Kartikeya Dwivedi 		return &bpf_kallsyms_lookup_name_proto;
583379a7f8bdSAlexei Starovoitov 	default:
583479a7f8bdSAlexei Starovoitov 		return tracing_prog_func_proto(func_id, prog);
583579a7f8bdSAlexei Starovoitov 	}
583679a7f8bdSAlexei Starovoitov }
583779a7f8bdSAlexei Starovoitov 
583879a7f8bdSAlexei Starovoitov const struct bpf_verifier_ops bpf_syscall_verifier_ops = {
583979a7f8bdSAlexei Starovoitov 	.get_func_proto  = syscall_prog_func_proto,
584079a7f8bdSAlexei Starovoitov 	.is_valid_access = syscall_prog_is_valid_access,
584179a7f8bdSAlexei Starovoitov };
584279a7f8bdSAlexei Starovoitov 
584379a7f8bdSAlexei Starovoitov const struct bpf_prog_ops bpf_syscall_prog_ops = {
584479a7f8bdSAlexei Starovoitov 	.test_run = bpf_prog_test_run_syscall,
584579a7f8bdSAlexei Starovoitov };
58462900005eSYan Zhu 
58472900005eSYan Zhu #ifdef CONFIG_SYSCTL
58482900005eSYan Zhu static int bpf_stats_handler(struct ctl_table *table, int write,
58492900005eSYan Zhu 			     void *buffer, size_t *lenp, loff_t *ppos)
58502900005eSYan Zhu {
58512900005eSYan Zhu 	struct static_key *key = (struct static_key *)table->data;
58522900005eSYan Zhu 	static int saved_val;
58532900005eSYan Zhu 	int val, ret;
58542900005eSYan Zhu 	struct ctl_table tmp = {
58552900005eSYan Zhu 		.data   = &val,
58562900005eSYan Zhu 		.maxlen = sizeof(val),
58572900005eSYan Zhu 		.mode   = table->mode,
58582900005eSYan Zhu 		.extra1 = SYSCTL_ZERO,
58592900005eSYan Zhu 		.extra2 = SYSCTL_ONE,
58602900005eSYan Zhu 	};
58612900005eSYan Zhu 
58622900005eSYan Zhu 	if (write && !capable(CAP_SYS_ADMIN))
58632900005eSYan Zhu 		return -EPERM;
58642900005eSYan Zhu 
58652900005eSYan Zhu 	mutex_lock(&bpf_stats_enabled_mutex);
58662900005eSYan Zhu 	val = saved_val;
58672900005eSYan Zhu 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
58682900005eSYan Zhu 	if (write && !ret && val != saved_val) {
58692900005eSYan Zhu 		if (val)
58702900005eSYan Zhu 			static_key_slow_inc(key);
58712900005eSYan Zhu 		else
58722900005eSYan Zhu 			static_key_slow_dec(key);
58732900005eSYan Zhu 		saved_val = val;
58742900005eSYan Zhu 	}
58752900005eSYan Zhu 	mutex_unlock(&bpf_stats_enabled_mutex);
58762900005eSYan Zhu 	return ret;
58772900005eSYan Zhu }
58782900005eSYan Zhu 
58792900005eSYan Zhu void __weak unpriv_ebpf_notify(int new_state)
58802900005eSYan Zhu {
58812900005eSYan Zhu }
58822900005eSYan Zhu 
58832900005eSYan Zhu static int bpf_unpriv_handler(struct ctl_table *table, int write,
58842900005eSYan Zhu 			      void *buffer, size_t *lenp, loff_t *ppos)
58852900005eSYan Zhu {
58862900005eSYan Zhu 	int ret, unpriv_enable = *(int *)table->data;
58872900005eSYan Zhu 	bool locked_state = unpriv_enable == 1;
58882900005eSYan Zhu 	struct ctl_table tmp = *table;
58892900005eSYan Zhu 
58902900005eSYan Zhu 	if (write && !capable(CAP_SYS_ADMIN))
58912900005eSYan Zhu 		return -EPERM;
58922900005eSYan Zhu 
58932900005eSYan Zhu 	tmp.data = &unpriv_enable;
58942900005eSYan Zhu 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
58952900005eSYan Zhu 	if (write && !ret) {
58962900005eSYan Zhu 		if (locked_state && unpriv_enable != 1)
58972900005eSYan Zhu 			return -EPERM;
58982900005eSYan Zhu 		*(int *)table->data = unpriv_enable;
58992900005eSYan Zhu 	}
59002900005eSYan Zhu 
5901fedf9920SKui-Feng Lee 	if (write)
59022900005eSYan Zhu 		unpriv_ebpf_notify(unpriv_enable);
59032900005eSYan Zhu 
59042900005eSYan Zhu 	return ret;
59052900005eSYan Zhu }
59062900005eSYan Zhu 
59072900005eSYan Zhu static struct ctl_table bpf_syscall_table[] = {
59082900005eSYan Zhu 	{
59092900005eSYan Zhu 		.procname	= "unprivileged_bpf_disabled",
59102900005eSYan Zhu 		.data		= &sysctl_unprivileged_bpf_disabled,
59112900005eSYan Zhu 		.maxlen		= sizeof(sysctl_unprivileged_bpf_disabled),
59122900005eSYan Zhu 		.mode		= 0644,
59132900005eSYan Zhu 		.proc_handler	= bpf_unpriv_handler,
59142900005eSYan Zhu 		.extra1		= SYSCTL_ZERO,
59152900005eSYan Zhu 		.extra2		= SYSCTL_TWO,
59162900005eSYan Zhu 	},
59172900005eSYan Zhu 	{
59182900005eSYan Zhu 		.procname	= "bpf_stats_enabled",
59192900005eSYan Zhu 		.data		= &bpf_stats_enabled_key.key,
59202900005eSYan Zhu 		.mode		= 0644,
59212900005eSYan Zhu 		.proc_handler	= bpf_stats_handler,
59222900005eSYan Zhu 	},
59232900005eSYan Zhu 	{ }
59242900005eSYan Zhu };
59252900005eSYan Zhu 
59262900005eSYan Zhu static int __init bpf_syscall_sysctl_init(void)
59272900005eSYan Zhu {
59282900005eSYan Zhu 	register_sysctl_init("kernel", bpf_syscall_table);
59292900005eSYan Zhu 	return 0;
59302900005eSYan Zhu }
59312900005eSYan Zhu late_initcall(bpf_syscall_sysctl_init);
59322900005eSYan Zhu #endif /* CONFIG_SYSCTL */
5933