xref: /linux/kernel/bpf/syscall.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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  */
bpf_check_uarg_tail_zero(bpfptr_t uaddr,size_t expected_size,size_t actual_size)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 
bpf_map_write_active_inc(struct bpf_map * map)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 
bpf_map_write_active_dec(struct bpf_map * map)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 
bpf_map_write_active(const struct bpf_map * map)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 
bpf_map_value_size(const struct bpf_map * map)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 
maybe_wait_bpf_programs(struct bpf_map * map)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 
bpf_map_update_value(struct bpf_map * map,struct file * map_file,void * key,void * value,__u64 flags)1583af43ba4SHou Tao static int bpf_map_update_value(struct bpf_map *map, struct file *map_file,
1593af43ba4SHou Tao 				void *key, void *value, __u64 flags)
16015c14a3dSBrian Vazquez {
16115c14a3dSBrian Vazquez 	int err;
16215c14a3dSBrian Vazquez 
16315c14a3dSBrian Vazquez 	/* Need to create a kthread, thus must support schedule */
1649d03ebc7SStanislav Fomichev 	if (bpf_map_is_offloaded(map)) {
16515c14a3dSBrian Vazquez 		return bpf_map_offload_update_elem(map, key, value, flags);
16615c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_CPUMAP ||
16731746031SAlexei Starovoitov 		   map->map_type == BPF_MAP_TYPE_ARENA ||
16815c14a3dSBrian Vazquez 		   map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
16915c14a3dSBrian Vazquez 		return map->ops->map_update_elem(map, key, value, flags);
17013b79d3fSLorenz Bauer 	} else if (map->map_type == BPF_MAP_TYPE_SOCKHASH ||
17113b79d3fSLorenz Bauer 		   map->map_type == BPF_MAP_TYPE_SOCKMAP) {
17213b79d3fSLorenz Bauer 		return sock_map_update_elem_sys(map, key, value, flags);
17315c14a3dSBrian Vazquez 	} else if (IS_FD_PROG_ARRAY(map)) {
1743af43ba4SHou Tao 		return bpf_fd_array_map_update_elem(map, map_file, key, value,
17515c14a3dSBrian Vazquez 						    flags);
17615c14a3dSBrian Vazquez 	}
17715c14a3dSBrian Vazquez 
178b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
17915c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
18015c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
18115c14a3dSBrian Vazquez 		err = bpf_percpu_hash_update(map, key, value, flags);
18215c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
18315c14a3dSBrian Vazquez 		err = bpf_percpu_array_update(map, key, value, flags);
18415c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
18515c14a3dSBrian Vazquez 		err = bpf_percpu_cgroup_storage_update(map, key, value,
18615c14a3dSBrian Vazquez 						       flags);
18715c14a3dSBrian Vazquez 	} else if (IS_FD_ARRAY(map)) {
1883af43ba4SHou Tao 		err = bpf_fd_array_map_update_elem(map, map_file, key, value,
18915c14a3dSBrian Vazquez 						   flags);
19015c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {
1913af43ba4SHou Tao 		err = bpf_fd_htab_map_update_elem(map, map_file, key, value,
19215c14a3dSBrian Vazquez 						  flags);
19315c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
19415c14a3dSBrian Vazquez 		/* rcu_read_lock() is not needed */
19515c14a3dSBrian Vazquez 		err = bpf_fd_reuseport_array_update_elem(map, key, value,
19615c14a3dSBrian Vazquez 							 flags);
19715c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
1989330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_STACK ||
1999330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) {
20015c14a3dSBrian Vazquez 		err = map->ops->map_push_elem(map, value, flags);
20115c14a3dSBrian Vazquez 	} else {
20215c14a3dSBrian Vazquez 		rcu_read_lock();
20315c14a3dSBrian Vazquez 		err = map->ops->map_update_elem(map, key, value, flags);
20415c14a3dSBrian Vazquez 		rcu_read_unlock();
20515c14a3dSBrian Vazquez 	}
206b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
20715c14a3dSBrian Vazquez 
20815c14a3dSBrian Vazquez 	return err;
20915c14a3dSBrian Vazquez }
21015c14a3dSBrian Vazquez 
bpf_map_copy_value(struct bpf_map * map,void * key,void * value,__u64 flags)21115c14a3dSBrian Vazquez static int bpf_map_copy_value(struct bpf_map *map, void *key, void *value,
21215c14a3dSBrian Vazquez 			      __u64 flags)
21315c14a3dSBrian Vazquez {
21415c14a3dSBrian Vazquez 	void *ptr;
21515c14a3dSBrian Vazquez 	int err;
21615c14a3dSBrian Vazquez 
2179d03ebc7SStanislav Fomichev 	if (bpf_map_is_offloaded(map))
218cb4d03abSBrian Vazquez 		return bpf_map_offload_lookup_elem(map, key, value);
21915c14a3dSBrian Vazquez 
220b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
22115c14a3dSBrian Vazquez 	if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
22215c14a3dSBrian Vazquez 	    map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
22315c14a3dSBrian Vazquez 		err = bpf_percpu_hash_copy(map, key, value);
22415c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
22515c14a3dSBrian Vazquez 		err = bpf_percpu_array_copy(map, key, value);
22615c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE) {
22715c14a3dSBrian Vazquez 		err = bpf_percpu_cgroup_storage_copy(map, key, value);
22815c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) {
22915c14a3dSBrian Vazquez 		err = bpf_stackmap_copy(map, key, value);
23015c14a3dSBrian Vazquez 	} else if (IS_FD_ARRAY(map) || IS_FD_PROG_ARRAY(map)) {
23115c14a3dSBrian Vazquez 		err = bpf_fd_array_map_lookup_elem(map, key, value);
23215c14a3dSBrian Vazquez 	} else if (IS_FD_HASH(map)) {
23315c14a3dSBrian Vazquez 		err = bpf_fd_htab_map_lookup_elem(map, key, value);
23415c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY) {
23515c14a3dSBrian Vazquez 		err = bpf_fd_reuseport_array_lookup_elem(map, key, value);
23615c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_QUEUE ||
2379330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_STACK ||
2389330986cSJoanne Koong 		   map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) {
23915c14a3dSBrian Vazquez 		err = map->ops->map_peek_elem(map, value);
24015c14a3dSBrian Vazquez 	} else if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
24115c14a3dSBrian Vazquez 		/* struct_ops map requires directly updating "value" */
24215c14a3dSBrian Vazquez 		err = bpf_struct_ops_map_sys_lookup_elem(map, key, value);
24315c14a3dSBrian Vazquez 	} else {
24415c14a3dSBrian Vazquez 		rcu_read_lock();
24515c14a3dSBrian Vazquez 		if (map->ops->map_lookup_elem_sys_only)
24615c14a3dSBrian Vazquez 			ptr = map->ops->map_lookup_elem_sys_only(map, key);
24715c14a3dSBrian Vazquez 		else
24815c14a3dSBrian Vazquez 			ptr = map->ops->map_lookup_elem(map, key);
24915c14a3dSBrian Vazquez 		if (IS_ERR(ptr)) {
25015c14a3dSBrian Vazquez 			err = PTR_ERR(ptr);
25115c14a3dSBrian Vazquez 		} else if (!ptr) {
25215c14a3dSBrian Vazquez 			err = -ENOENT;
25315c14a3dSBrian Vazquez 		} else {
25415c14a3dSBrian Vazquez 			err = 0;
25515c14a3dSBrian Vazquez 			if (flags & BPF_F_LOCK)
25615c14a3dSBrian Vazquez 				/* lock 'ptr' and copy everything but lock */
25715c14a3dSBrian Vazquez 				copy_map_value_locked(map, value, ptr, true);
25815c14a3dSBrian Vazquez 			else
25915c14a3dSBrian Vazquez 				copy_map_value(map, value, ptr);
26068134668SAlexei Starovoitov 			/* mask lock and timer, since value wasn't zero inited */
26168134668SAlexei Starovoitov 			check_and_init_map_value(map, value);
26215c14a3dSBrian Vazquez 		}
26315c14a3dSBrian Vazquez 		rcu_read_unlock();
26415c14a3dSBrian Vazquez 	}
26515c14a3dSBrian Vazquez 
266b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
26715c14a3dSBrian Vazquez 
26815c14a3dSBrian Vazquez 	return err;
26915c14a3dSBrian Vazquez }
27015c14a3dSBrian Vazquez 
271d5299b67SRoman Gushchin /* Please, do not use this function outside from the map creation path
272d5299b67SRoman Gushchin  * (e.g. in map update path) without taking care of setting the active
273d5299b67SRoman Gushchin  * memory cgroup (see at bpf_map_kmalloc_node() for example).
274d5299b67SRoman Gushchin  */
__bpf_map_area_alloc(u64 size,int numa_node,bool mmapable)275196e8ca7SDaniel Borkmann static void *__bpf_map_area_alloc(u64 size, int numa_node, bool mmapable)
276d407bd25SDaniel Borkmann {
277f01a7dbeSMartynas Pumputis 	/* We really just want to fail instead of triggering OOM killer
278f01a7dbeSMartynas Pumputis 	 * under memory pressure, therefore we set __GFP_NORETRY to kmalloc,
279f01a7dbeSMartynas Pumputis 	 * which is used for lower order allocation requests.
280f01a7dbeSMartynas Pumputis 	 *
281f01a7dbeSMartynas Pumputis 	 * It has been observed that higher order allocation requests done by
282f01a7dbeSMartynas Pumputis 	 * vmalloc with __GFP_NORETRY being set might fail due to not trying
283f01a7dbeSMartynas Pumputis 	 * to reclaim memory from the page cache, thus we set
284f01a7dbeSMartynas Pumputis 	 * __GFP_RETRY_MAYFAIL to avoid such situations.
285d407bd25SDaniel Borkmann 	 */
286f01a7dbeSMartynas Pumputis 
287ee53cbfbSYafang Shao 	gfp_t gfp = bpf_memcg_flags(__GFP_NOWARN | __GFP_ZERO);
288041de93fSChristoph Hellwig 	unsigned int flags = 0;
289041de93fSChristoph Hellwig 	unsigned long align = 1;
290d407bd25SDaniel Borkmann 	void *area;
291d407bd25SDaniel Borkmann 
292196e8ca7SDaniel Borkmann 	if (size >= SIZE_MAX)
293196e8ca7SDaniel Borkmann 		return NULL;
294196e8ca7SDaniel Borkmann 
295fc970227SAndrii Nakryiko 	/* kmalloc()'ed memory can't be mmap()'ed */
296041de93fSChristoph Hellwig 	if (mmapable) {
297041de93fSChristoph Hellwig 		BUG_ON(!PAGE_ALIGNED(size));
298041de93fSChristoph Hellwig 		align = SHMLBA;
299041de93fSChristoph Hellwig 		flags = VM_USERMAP;
300041de93fSChristoph Hellwig 	} else if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
301041de93fSChristoph Hellwig 		area = kmalloc_node(size, gfp | GFP_USER | __GFP_NORETRY,
302f01a7dbeSMartynas Pumputis 				    numa_node);
303d407bd25SDaniel Borkmann 		if (area != NULL)
304d407bd25SDaniel Borkmann 			return area;
305d407bd25SDaniel Borkmann 	}
306041de93fSChristoph Hellwig 
307041de93fSChristoph Hellwig 	return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
308041de93fSChristoph Hellwig 			gfp | GFP_KERNEL | __GFP_RETRY_MAYFAIL, PAGE_KERNEL,
309041de93fSChristoph Hellwig 			flags, numa_node, __builtin_return_address(0));
310d407bd25SDaniel Borkmann }
311d407bd25SDaniel Borkmann 
bpf_map_area_alloc(u64 size,int numa_node)312196e8ca7SDaniel Borkmann void *bpf_map_area_alloc(u64 size, int numa_node)
313fc970227SAndrii Nakryiko {
314fc970227SAndrii Nakryiko 	return __bpf_map_area_alloc(size, numa_node, false);
315fc970227SAndrii Nakryiko }
316fc970227SAndrii Nakryiko 
bpf_map_area_mmapable_alloc(u64 size,int numa_node)317196e8ca7SDaniel Borkmann void *bpf_map_area_mmapable_alloc(u64 size, int numa_node)
318fc970227SAndrii Nakryiko {
319fc970227SAndrii Nakryiko 	return __bpf_map_area_alloc(size, numa_node, true);
320fc970227SAndrii Nakryiko }
321fc970227SAndrii Nakryiko 
bpf_map_area_free(void * area)322d407bd25SDaniel Borkmann void bpf_map_area_free(void *area)
323d407bd25SDaniel Borkmann {
324d407bd25SDaniel Borkmann 	kvfree(area);
325d407bd25SDaniel Borkmann }
326d407bd25SDaniel Borkmann 
bpf_map_flags_retain_permanent(u32 flags)327be70bcd5SDaniel Borkmann static u32 bpf_map_flags_retain_permanent(u32 flags)
328be70bcd5SDaniel Borkmann {
329be70bcd5SDaniel Borkmann 	/* Some map creation flags are not tied to the map object but
330be70bcd5SDaniel Borkmann 	 * rather to the map fd instead, so they have no meaning upon
331be70bcd5SDaniel Borkmann 	 * map object inspection since multiple file descriptors with
332be70bcd5SDaniel Borkmann 	 * different (access) properties can exist here. Thus, given
333be70bcd5SDaniel Borkmann 	 * this has zero meaning for the map itself, lets clear these
334be70bcd5SDaniel Borkmann 	 * from here.
335be70bcd5SDaniel Borkmann 	 */
336be70bcd5SDaniel Borkmann 	return flags & ~(BPF_F_RDONLY | BPF_F_WRONLY);
337be70bcd5SDaniel Borkmann }
338be70bcd5SDaniel Borkmann 
bpf_map_init_from_attr(struct bpf_map * map,union bpf_attr * attr)339bd475643SJakub Kicinski void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr)
340bd475643SJakub Kicinski {
341bd475643SJakub Kicinski 	map->map_type = attr->map_type;
342bd475643SJakub Kicinski 	map->key_size = attr->key_size;
343bd475643SJakub Kicinski 	map->value_size = attr->value_size;
344bd475643SJakub Kicinski 	map->max_entries = attr->max_entries;
345be70bcd5SDaniel Borkmann 	map->map_flags = bpf_map_flags_retain_permanent(attr->map_flags);
346bd475643SJakub Kicinski 	map->numa_node = bpf_map_attr_numa_node(attr);
3479330986cSJoanne Koong 	map->map_extra = attr->map_extra;
348bd475643SJakub Kicinski }
349bd475643SJakub Kicinski 
bpf_map_alloc_id(struct bpf_map * map)350f3f1c054SMartin KaFai Lau static int bpf_map_alloc_id(struct bpf_map *map)
351f3f1c054SMartin KaFai Lau {
352f3f1c054SMartin KaFai Lau 	int id;
353f3f1c054SMartin KaFai Lau 
354b76354cdSShaohua Li 	idr_preload(GFP_KERNEL);
355f3f1c054SMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
356f3f1c054SMartin KaFai Lau 	id = idr_alloc_cyclic(&map_idr, map, 1, INT_MAX, GFP_ATOMIC);
357f3f1c054SMartin KaFai Lau 	if (id > 0)
358f3f1c054SMartin KaFai Lau 		map->id = id;
359f3f1c054SMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
360b76354cdSShaohua Li 	idr_preload_end();
361f3f1c054SMartin KaFai Lau 
362f3f1c054SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
363f3f1c054SMartin KaFai Lau 		return -ENOSPC;
364f3f1c054SMartin KaFai Lau 
365f3f1c054SMartin KaFai Lau 	return id > 0 ? 0 : id;
366f3f1c054SMartin KaFai Lau }
367f3f1c054SMartin KaFai Lau 
bpf_map_free_id(struct bpf_map * map)368158e5e9eSTobias Klauser void bpf_map_free_id(struct bpf_map *map)
369f3f1c054SMartin KaFai Lau {
370930651a7SEric Dumazet 	unsigned long flags;
371930651a7SEric Dumazet 
372a3884572SJakub Kicinski 	/* Offloaded maps are removed from the IDR store when their device
373a3884572SJakub Kicinski 	 * disappears - even if someone holds an fd to them they are unusable,
374a3884572SJakub Kicinski 	 * the memory is gone, all ops will fail; they are simply waiting for
375a3884572SJakub Kicinski 	 * refcnt to drop to be freed.
376a3884572SJakub Kicinski 	 */
377a3884572SJakub Kicinski 	if (!map->id)
378a3884572SJakub Kicinski 		return;
379a3884572SJakub Kicinski 
380930651a7SEric Dumazet 	spin_lock_irqsave(&map_idr_lock, flags);
381bd5f5f4eSMartin KaFai Lau 
382f3f1c054SMartin KaFai Lau 	idr_remove(&map_idr, map->id);
383a3884572SJakub Kicinski 	map->id = 0;
384bd5f5f4eSMartin KaFai Lau 
385930651a7SEric Dumazet 	spin_unlock_irqrestore(&map_idr_lock, flags);
386f3f1c054SMartin KaFai Lau }
387f3f1c054SMartin KaFai Lau 
3883a3b7fecSJohannes Weiner #ifdef CONFIG_MEMCG
bpf_map_save_memcg(struct bpf_map * map)38948edc1f7SRoman Gushchin static void bpf_map_save_memcg(struct bpf_map *map)
39048edc1f7SRoman Gushchin {
3914201d9abSRoman Gushchin 	/* Currently if a map is created by a process belonging to the root
3924201d9abSRoman Gushchin 	 * memory cgroup, get_obj_cgroup_from_current() will return NULL.
3934201d9abSRoman Gushchin 	 * So we have to check map->objcg for being NULL each time it's
3944201d9abSRoman Gushchin 	 * being used.
3954201d9abSRoman Gushchin 	 */
396ee53cbfbSYafang Shao 	if (memcg_bpf_enabled())
3974201d9abSRoman Gushchin 		map->objcg = get_obj_cgroup_from_current();
39848edc1f7SRoman Gushchin }
39948edc1f7SRoman Gushchin 
bpf_map_release_memcg(struct bpf_map * map)40048edc1f7SRoman Gushchin static void bpf_map_release_memcg(struct bpf_map *map)
40148edc1f7SRoman Gushchin {
4024201d9abSRoman Gushchin 	if (map->objcg)
4034201d9abSRoman Gushchin 		obj_cgroup_put(map->objcg);
4044201d9abSRoman Gushchin }
4054201d9abSRoman Gushchin 
bpf_map_get_memcg(const struct bpf_map * map)4064201d9abSRoman Gushchin static struct mem_cgroup *bpf_map_get_memcg(const struct bpf_map *map)
4074201d9abSRoman Gushchin {
4084201d9abSRoman Gushchin 	if (map->objcg)
4094201d9abSRoman Gushchin 		return get_mem_cgroup_from_objcg(map->objcg);
4104201d9abSRoman Gushchin 
4114201d9abSRoman Gushchin 	return root_mem_cgroup;
41248edc1f7SRoman Gushchin }
41348edc1f7SRoman Gushchin 
bpf_map_kmalloc_node(const struct bpf_map * map,size_t size,gfp_t flags,int node)41448edc1f7SRoman Gushchin void *bpf_map_kmalloc_node(const struct bpf_map *map, size_t size, gfp_t flags,
41548edc1f7SRoman Gushchin 			   int node)
41648edc1f7SRoman Gushchin {
4174201d9abSRoman Gushchin 	struct mem_cgroup *memcg, *old_memcg;
41848edc1f7SRoman Gushchin 	void *ptr;
41948edc1f7SRoman Gushchin 
4204201d9abSRoman Gushchin 	memcg = bpf_map_get_memcg(map);
4214201d9abSRoman Gushchin 	old_memcg = set_active_memcg(memcg);
42248edc1f7SRoman Gushchin 	ptr = kmalloc_node(size, flags | __GFP_ACCOUNT, node);
42348edc1f7SRoman Gushchin 	set_active_memcg(old_memcg);
4244201d9abSRoman Gushchin 	mem_cgroup_put(memcg);
42548edc1f7SRoman Gushchin 
42648edc1f7SRoman Gushchin 	return ptr;
42748edc1f7SRoman Gushchin }
42848edc1f7SRoman Gushchin 
bpf_map_kzalloc(const struct bpf_map * map,size_t size,gfp_t flags)42948edc1f7SRoman Gushchin void *bpf_map_kzalloc(const struct bpf_map *map, size_t size, gfp_t flags)
43048edc1f7SRoman Gushchin {
4314201d9abSRoman Gushchin 	struct mem_cgroup *memcg, *old_memcg;
43248edc1f7SRoman Gushchin 	void *ptr;
43348edc1f7SRoman Gushchin 
4344201d9abSRoman Gushchin 	memcg = bpf_map_get_memcg(map);
4354201d9abSRoman Gushchin 	old_memcg = set_active_memcg(memcg);
43648edc1f7SRoman Gushchin 	ptr = kzalloc(size, flags | __GFP_ACCOUNT);
43748edc1f7SRoman Gushchin 	set_active_memcg(old_memcg);
4384201d9abSRoman Gushchin 	mem_cgroup_put(memcg);
43948edc1f7SRoman Gushchin 
44048edc1f7SRoman Gushchin 	return ptr;
44148edc1f7SRoman Gushchin }
44248edc1f7SRoman Gushchin 
bpf_map_kvcalloc(struct bpf_map * map,size_t n,size_t size,gfp_t flags)443ddef81b5SYafang Shao void *bpf_map_kvcalloc(struct bpf_map *map, size_t n, size_t size,
444ddef81b5SYafang Shao 		       gfp_t flags)
445ddef81b5SYafang Shao {
446ddef81b5SYafang Shao 	struct mem_cgroup *memcg, *old_memcg;
447ddef81b5SYafang Shao 	void *ptr;
448ddef81b5SYafang Shao 
449ddef81b5SYafang Shao 	memcg = bpf_map_get_memcg(map);
450ddef81b5SYafang Shao 	old_memcg = set_active_memcg(memcg);
451ddef81b5SYafang Shao 	ptr = kvcalloc(n, size, flags | __GFP_ACCOUNT);
452ddef81b5SYafang Shao 	set_active_memcg(old_memcg);
453ddef81b5SYafang Shao 	mem_cgroup_put(memcg);
454ddef81b5SYafang Shao 
455ddef81b5SYafang Shao 	return ptr;
456ddef81b5SYafang Shao }
457ddef81b5SYafang Shao 
bpf_map_alloc_percpu(const struct bpf_map * map,size_t size,size_t align,gfp_t flags)45848edc1f7SRoman Gushchin void __percpu *bpf_map_alloc_percpu(const struct bpf_map *map, size_t size,
45948edc1f7SRoman Gushchin 				    size_t align, gfp_t flags)
46048edc1f7SRoman Gushchin {
4614201d9abSRoman Gushchin 	struct mem_cgroup *memcg, *old_memcg;
46248edc1f7SRoman Gushchin 	void __percpu *ptr;
46348edc1f7SRoman Gushchin 
4644201d9abSRoman Gushchin 	memcg = bpf_map_get_memcg(map);
4654201d9abSRoman Gushchin 	old_memcg = set_active_memcg(memcg);
46648edc1f7SRoman Gushchin 	ptr = __alloc_percpu_gfp(size, align, flags | __GFP_ACCOUNT);
46748edc1f7SRoman Gushchin 	set_active_memcg(old_memcg);
4684201d9abSRoman Gushchin 	mem_cgroup_put(memcg);
46948edc1f7SRoman Gushchin 
47048edc1f7SRoman Gushchin 	return ptr;
47148edc1f7SRoman Gushchin }
47248edc1f7SRoman Gushchin 
47348edc1f7SRoman Gushchin #else
bpf_map_save_memcg(struct bpf_map * map)47448edc1f7SRoman Gushchin static void bpf_map_save_memcg(struct bpf_map *map)
47548edc1f7SRoman Gushchin {
47648edc1f7SRoman Gushchin }
47748edc1f7SRoman Gushchin 
bpf_map_release_memcg(struct bpf_map * map)47848edc1f7SRoman Gushchin static void bpf_map_release_memcg(struct bpf_map *map)
47948edc1f7SRoman Gushchin {
48048edc1f7SRoman Gushchin }
48148edc1f7SRoman Gushchin #endif
48248edc1f7SRoman Gushchin 
bpf_map_alloc_pages(const struct bpf_map * map,gfp_t gfp,int nid,unsigned long nr_pages,struct page ** pages)48331746031SAlexei Starovoitov int bpf_map_alloc_pages(const struct bpf_map *map, gfp_t gfp, int nid,
48431746031SAlexei Starovoitov 			unsigned long nr_pages, struct page **pages)
48531746031SAlexei Starovoitov {
48631746031SAlexei Starovoitov 	unsigned long i, j;
48731746031SAlexei Starovoitov 	struct page *pg;
48831746031SAlexei Starovoitov 	int ret = 0;
4893a3b7fecSJohannes Weiner #ifdef CONFIG_MEMCG
49031746031SAlexei Starovoitov 	struct mem_cgroup *memcg, *old_memcg;
49131746031SAlexei Starovoitov 
49231746031SAlexei Starovoitov 	memcg = bpf_map_get_memcg(map);
49331746031SAlexei Starovoitov 	old_memcg = set_active_memcg(memcg);
49431746031SAlexei Starovoitov #endif
49531746031SAlexei Starovoitov 	for (i = 0; i < nr_pages; i++) {
49631746031SAlexei Starovoitov 		pg = alloc_pages_node(nid, gfp | __GFP_ACCOUNT, 0);
49731746031SAlexei Starovoitov 
49831746031SAlexei Starovoitov 		if (pg) {
49931746031SAlexei Starovoitov 			pages[i] = pg;
50031746031SAlexei Starovoitov 			continue;
50131746031SAlexei Starovoitov 		}
50231746031SAlexei Starovoitov 		for (j = 0; j < i; j++)
50331746031SAlexei Starovoitov 			__free_page(pages[j]);
50431746031SAlexei Starovoitov 		ret = -ENOMEM;
50531746031SAlexei Starovoitov 		break;
50631746031SAlexei Starovoitov 	}
50731746031SAlexei Starovoitov 
5083a3b7fecSJohannes Weiner #ifdef CONFIG_MEMCG
50931746031SAlexei Starovoitov 	set_active_memcg(old_memcg);
51031746031SAlexei Starovoitov 	mem_cgroup_put(memcg);
51131746031SAlexei Starovoitov #endif
51231746031SAlexei Starovoitov 	return ret;
51331746031SAlexei Starovoitov }
51431746031SAlexei Starovoitov 
51531746031SAlexei Starovoitov 
btf_field_cmp(const void * a,const void * b)516aa3496acSKumar Kartikeya Dwivedi static int btf_field_cmp(const void *a, const void *b)
51761df10c7SKumar Kartikeya Dwivedi {
518aa3496acSKumar Kartikeya Dwivedi 	const struct btf_field *f1 = a, *f2 = b;
51961df10c7SKumar Kartikeya Dwivedi 
520aa3496acSKumar Kartikeya Dwivedi 	if (f1->offset < f2->offset)
52161df10c7SKumar Kartikeya Dwivedi 		return -1;
522aa3496acSKumar Kartikeya Dwivedi 	else if (f1->offset > f2->offset)
52361df10c7SKumar Kartikeya Dwivedi 		return 1;
52461df10c7SKumar Kartikeya Dwivedi 	return 0;
52561df10c7SKumar Kartikeya Dwivedi }
52661df10c7SKumar Kartikeya Dwivedi 
btf_record_find(const struct btf_record * rec,u32 offset,u32 field_mask)527aa3496acSKumar Kartikeya Dwivedi struct btf_field *btf_record_find(const struct btf_record *rec, u32 offset,
52874843b57SDave Marchevsky 				  u32 field_mask)
52961df10c7SKumar Kartikeya Dwivedi {
530aa3496acSKumar Kartikeya Dwivedi 	struct btf_field *field;
53161df10c7SKumar Kartikeya Dwivedi 
53274843b57SDave Marchevsky 	if (IS_ERR_OR_NULL(rec) || !(rec->field_mask & field_mask))
53361df10c7SKumar Kartikeya Dwivedi 		return NULL;
534aa3496acSKumar Kartikeya Dwivedi 	field = bsearch(&offset, rec->fields, rec->cnt, sizeof(rec->fields[0]), btf_field_cmp);
53574843b57SDave Marchevsky 	if (!field || !(field->type & field_mask))
536aa3496acSKumar Kartikeya Dwivedi 		return NULL;
537aa3496acSKumar Kartikeya Dwivedi 	return field;
53861df10c7SKumar Kartikeya Dwivedi }
53961df10c7SKumar Kartikeya Dwivedi 
btf_record_free(struct btf_record * rec)540aa3496acSKumar Kartikeya Dwivedi void btf_record_free(struct btf_record *rec)
54161df10c7SKumar Kartikeya Dwivedi {
54261df10c7SKumar Kartikeya Dwivedi 	int i;
54361df10c7SKumar Kartikeya Dwivedi 
544aa3496acSKumar Kartikeya Dwivedi 	if (IS_ERR_OR_NULL(rec))
54561df10c7SKumar Kartikeya Dwivedi 		return;
546aa3496acSKumar Kartikeya Dwivedi 	for (i = 0; i < rec->cnt; i++) {
547aa3496acSKumar Kartikeya Dwivedi 		switch (rec->fields[i].type) {
548aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_UNREF:
549aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_REF:
55055db92f4SYonghong Song 		case BPF_KPTR_PERCPU:
551aa3496acSKumar Kartikeya Dwivedi 			if (rec->fields[i].kptr.module)
552aa3496acSKumar Kartikeya Dwivedi 				module_put(rec->fields[i].kptr.module);
553aa3496acSKumar Kartikeya Dwivedi 			btf_put(rec->fields[i].kptr.btf);
554aa3496acSKumar Kartikeya Dwivedi 			break;
555f0c5941fSKumar Kartikeya Dwivedi 		case BPF_LIST_HEAD:
5568ffa5cc1SKumar Kartikeya Dwivedi 		case BPF_LIST_NODE:
5579c395c1bSDave Marchevsky 		case BPF_RB_ROOT:
5589c395c1bSDave Marchevsky 		case BPF_RB_NODE:
5599c395c1bSDave Marchevsky 		case BPF_SPIN_LOCK:
5609c395c1bSDave Marchevsky 		case BPF_TIMER:
561d54730b5SDave Marchevsky 		case BPF_REFCOUNT:
562d56b63cfSBenjamin Tissoires 		case BPF_WORKQUEUE:
5639c395c1bSDave Marchevsky 			/* Nothing to release */
564f0c5941fSKumar Kartikeya Dwivedi 			break;
565aa3496acSKumar Kartikeya Dwivedi 		default:
566aa3496acSKumar Kartikeya Dwivedi 			WARN_ON_ONCE(1);
56714a324f6SKumar Kartikeya Dwivedi 			continue;
56814a324f6SKumar Kartikeya Dwivedi 		}
569aa3496acSKumar Kartikeya Dwivedi 	}
570aa3496acSKumar Kartikeya Dwivedi 	kfree(rec);
571aa3496acSKumar Kartikeya Dwivedi }
572aa3496acSKumar Kartikeya Dwivedi 
bpf_map_free_record(struct bpf_map * map)573aa3496acSKumar Kartikeya Dwivedi void bpf_map_free_record(struct bpf_map *map)
574aa3496acSKumar Kartikeya Dwivedi {
575aa3496acSKumar Kartikeya Dwivedi 	btf_record_free(map->record);
576aa3496acSKumar Kartikeya Dwivedi 	map->record = NULL;
577aa3496acSKumar Kartikeya Dwivedi }
578aa3496acSKumar Kartikeya Dwivedi 
btf_record_dup(const struct btf_record * rec)579aa3496acSKumar Kartikeya Dwivedi struct btf_record *btf_record_dup(const struct btf_record *rec)
580aa3496acSKumar Kartikeya Dwivedi {
581aa3496acSKumar Kartikeya Dwivedi 	const struct btf_field *fields;
582aa3496acSKumar Kartikeya Dwivedi 	struct btf_record *new_rec;
583aa3496acSKumar Kartikeya Dwivedi 	int ret, size, i;
584aa3496acSKumar Kartikeya Dwivedi 
585aa3496acSKumar Kartikeya Dwivedi 	if (IS_ERR_OR_NULL(rec))
586aa3496acSKumar Kartikeya Dwivedi 		return NULL;
587aa3496acSKumar Kartikeya Dwivedi 	size = offsetof(struct btf_record, fields[rec->cnt]);
588aa3496acSKumar Kartikeya Dwivedi 	new_rec = kmemdup(rec, size, GFP_KERNEL | __GFP_NOWARN);
589aa3496acSKumar Kartikeya Dwivedi 	if (!new_rec)
590aa3496acSKumar Kartikeya Dwivedi 		return ERR_PTR(-ENOMEM);
591aa3496acSKumar Kartikeya Dwivedi 	/* Do a deep copy of the btf_record */
592aa3496acSKumar Kartikeya Dwivedi 	fields = rec->fields;
593aa3496acSKumar Kartikeya Dwivedi 	new_rec->cnt = 0;
594aa3496acSKumar Kartikeya Dwivedi 	for (i = 0; i < rec->cnt; i++) {
595aa3496acSKumar Kartikeya Dwivedi 		switch (fields[i].type) {
596aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_UNREF:
597aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_REF:
59855db92f4SYonghong Song 		case BPF_KPTR_PERCPU:
599aa3496acSKumar Kartikeya Dwivedi 			btf_get(fields[i].kptr.btf);
600aa3496acSKumar Kartikeya Dwivedi 			if (fields[i].kptr.module && !try_module_get(fields[i].kptr.module)) {
601aa3496acSKumar Kartikeya Dwivedi 				ret = -ENXIO;
602aa3496acSKumar Kartikeya Dwivedi 				goto free;
603aa3496acSKumar Kartikeya Dwivedi 			}
604aa3496acSKumar Kartikeya Dwivedi 			break;
605f0c5941fSKumar Kartikeya Dwivedi 		case BPF_LIST_HEAD:
6068ffa5cc1SKumar Kartikeya Dwivedi 		case BPF_LIST_NODE:
6079c395c1bSDave Marchevsky 		case BPF_RB_ROOT:
6089c395c1bSDave Marchevsky 		case BPF_RB_NODE:
6099c395c1bSDave Marchevsky 		case BPF_SPIN_LOCK:
6109c395c1bSDave Marchevsky 		case BPF_TIMER:
611d54730b5SDave Marchevsky 		case BPF_REFCOUNT:
612d56b63cfSBenjamin Tissoires 		case BPF_WORKQUEUE:
6139c395c1bSDave Marchevsky 			/* Nothing to acquire */
614f0c5941fSKumar Kartikeya Dwivedi 			break;
615aa3496acSKumar Kartikeya Dwivedi 		default:
616aa3496acSKumar Kartikeya Dwivedi 			ret = -EFAULT;
617aa3496acSKumar Kartikeya Dwivedi 			WARN_ON_ONCE(1);
618aa3496acSKumar Kartikeya Dwivedi 			goto free;
619aa3496acSKumar Kartikeya Dwivedi 		}
620aa3496acSKumar Kartikeya Dwivedi 		new_rec->cnt++;
621aa3496acSKumar Kartikeya Dwivedi 	}
622aa3496acSKumar Kartikeya Dwivedi 	return new_rec;
623aa3496acSKumar Kartikeya Dwivedi free:
624aa3496acSKumar Kartikeya Dwivedi 	btf_record_free(new_rec);
625aa3496acSKumar Kartikeya Dwivedi 	return ERR_PTR(ret);
626aa3496acSKumar Kartikeya Dwivedi }
627aa3496acSKumar Kartikeya Dwivedi 
btf_record_equal(const struct btf_record * rec_a,const struct btf_record * rec_b)628aa3496acSKumar Kartikeya Dwivedi bool btf_record_equal(const struct btf_record *rec_a, const struct btf_record *rec_b)
629aa3496acSKumar Kartikeya Dwivedi {
630aa3496acSKumar Kartikeya Dwivedi 	bool a_has_fields = !IS_ERR_OR_NULL(rec_a), b_has_fields = !IS_ERR_OR_NULL(rec_b);
631aa3496acSKumar Kartikeya Dwivedi 	int size;
632aa3496acSKumar Kartikeya Dwivedi 
633aa3496acSKumar Kartikeya Dwivedi 	if (!a_has_fields && !b_has_fields)
634aa3496acSKumar Kartikeya Dwivedi 		return true;
635aa3496acSKumar Kartikeya Dwivedi 	if (a_has_fields != b_has_fields)
636aa3496acSKumar Kartikeya Dwivedi 		return false;
637aa3496acSKumar Kartikeya Dwivedi 	if (rec_a->cnt != rec_b->cnt)
638aa3496acSKumar Kartikeya Dwivedi 		return false;
639aa3496acSKumar Kartikeya Dwivedi 	size = offsetof(struct btf_record, fields[rec_a->cnt]);
640c22dfdd2SKumar Kartikeya Dwivedi 	/* btf_parse_fields uses kzalloc to allocate a btf_record, so unused
641c22dfdd2SKumar Kartikeya Dwivedi 	 * members are zeroed out. So memcmp is safe to do without worrying
642c22dfdd2SKumar Kartikeya Dwivedi 	 * about padding/unused fields.
643c22dfdd2SKumar Kartikeya Dwivedi 	 *
644c22dfdd2SKumar Kartikeya Dwivedi 	 * While spin_lock, timer, and kptr have no relation to map BTF,
645c22dfdd2SKumar Kartikeya Dwivedi 	 * list_head metadata is specific to map BTF, the btf and value_rec
646c22dfdd2SKumar Kartikeya Dwivedi 	 * members in particular. btf is the map BTF, while value_rec points to
647c22dfdd2SKumar Kartikeya Dwivedi 	 * btf_record in that map BTF.
648c22dfdd2SKumar Kartikeya Dwivedi 	 *
649c22dfdd2SKumar Kartikeya Dwivedi 	 * So while by default, we don't rely on the map BTF (which the records
650c22dfdd2SKumar Kartikeya Dwivedi 	 * were parsed from) matching for both records, which is not backwards
651c22dfdd2SKumar Kartikeya Dwivedi 	 * compatible, in case list_head is part of it, we implicitly rely on
652c22dfdd2SKumar Kartikeya Dwivedi 	 * that by way of depending on memcmp succeeding for it.
653c22dfdd2SKumar Kartikeya Dwivedi 	 */
654aa3496acSKumar Kartikeya Dwivedi 	return !memcmp(rec_a, rec_b, size);
655aa3496acSKumar Kartikeya Dwivedi }
656aa3496acSKumar Kartikeya Dwivedi 
bpf_obj_free_timer(const struct btf_record * rec,void * obj)657db559117SKumar Kartikeya Dwivedi void bpf_obj_free_timer(const struct btf_record *rec, void *obj)
658db559117SKumar Kartikeya Dwivedi {
659db559117SKumar Kartikeya Dwivedi 	if (WARN_ON_ONCE(!btf_record_has_field(rec, BPF_TIMER)))
660db559117SKumar Kartikeya Dwivedi 		return;
661db559117SKumar Kartikeya Dwivedi 	bpf_timer_cancel_and_free(obj + rec->timer_off);
662db559117SKumar Kartikeya Dwivedi }
663db559117SKumar Kartikeya Dwivedi 
bpf_obj_free_workqueue(const struct btf_record * rec,void * obj)664246331e3SBenjamin Tissoires void bpf_obj_free_workqueue(const struct btf_record *rec, void *obj)
665246331e3SBenjamin Tissoires {
666246331e3SBenjamin Tissoires 	if (WARN_ON_ONCE(!btf_record_has_field(rec, BPF_WORKQUEUE)))
667246331e3SBenjamin Tissoires 		return;
668246331e3SBenjamin Tissoires 	bpf_wq_cancel_and_free(obj + rec->wq_off);
669246331e3SBenjamin Tissoires }
670246331e3SBenjamin Tissoires 
bpf_obj_free_fields(const struct btf_record * rec,void * obj)671aa3496acSKumar Kartikeya Dwivedi void bpf_obj_free_fields(const struct btf_record *rec, void *obj)
672aa3496acSKumar Kartikeya Dwivedi {
673aa3496acSKumar Kartikeya Dwivedi 	const struct btf_field *fields;
674aa3496acSKumar Kartikeya Dwivedi 	int i;
675aa3496acSKumar Kartikeya Dwivedi 
676aa3496acSKumar Kartikeya Dwivedi 	if (IS_ERR_OR_NULL(rec))
677aa3496acSKumar Kartikeya Dwivedi 		return;
678aa3496acSKumar Kartikeya Dwivedi 	fields = rec->fields;
679aa3496acSKumar Kartikeya Dwivedi 	for (i = 0; i < rec->cnt; i++) {
680c8e18754SDave Marchevsky 		struct btf_struct_meta *pointee_struct_meta;
681aa3496acSKumar Kartikeya Dwivedi 		const struct btf_field *field = &fields[i];
682aa3496acSKumar Kartikeya Dwivedi 		void *field_ptr = obj + field->offset;
683c8e18754SDave Marchevsky 		void *xchgd_field;
684aa3496acSKumar Kartikeya Dwivedi 
685aa3496acSKumar Kartikeya Dwivedi 		switch (fields[i].type) {
686db559117SKumar Kartikeya Dwivedi 		case BPF_SPIN_LOCK:
687db559117SKumar Kartikeya Dwivedi 			break;
688db559117SKumar Kartikeya Dwivedi 		case BPF_TIMER:
689db559117SKumar Kartikeya Dwivedi 			bpf_timer_cancel_and_free(field_ptr);
690db559117SKumar Kartikeya Dwivedi 			break;
691d56b63cfSBenjamin Tissoires 		case BPF_WORKQUEUE:
692246331e3SBenjamin Tissoires 			bpf_wq_cancel_and_free(field_ptr);
693d56b63cfSBenjamin Tissoires 			break;
694aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_UNREF:
695aa3496acSKumar Kartikeya Dwivedi 			WRITE_ONCE(*(u64 *)field_ptr, 0);
696aa3496acSKumar Kartikeya Dwivedi 			break;
697aa3496acSKumar Kartikeya Dwivedi 		case BPF_KPTR_REF:
69855db92f4SYonghong Song 		case BPF_KPTR_PERCPU:
699c8e18754SDave Marchevsky 			xchgd_field = (void *)xchg((unsigned long *)field_ptr, 0);
7001431d0b5SDavid Vernet 			if (!xchgd_field)
7011431d0b5SDavid Vernet 				break;
7021431d0b5SDavid Vernet 
703c8e18754SDave Marchevsky 			if (!btf_is_kernel(field->kptr.btf)) {
704c8e18754SDave Marchevsky 				pointee_struct_meta = btf_find_struct_meta(field->kptr.btf,
705c8e18754SDave Marchevsky 									   field->kptr.btf_id);
7069e36a204SDave Marchevsky 				migrate_disable();
7079e36a204SDave Marchevsky 				__bpf_obj_drop_impl(xchgd_field, pointee_struct_meta ?
708e383a459SHou Tao 								 pointee_struct_meta->record : NULL,
709e383a459SHou Tao 								 fields[i].type == BPF_KPTR_PERCPU);
7109e36a204SDave Marchevsky 				migrate_enable();
711c8e18754SDave Marchevsky 			} else {
712c8e18754SDave Marchevsky 				field->kptr.dtor(xchgd_field);
713c8e18754SDave Marchevsky 			}
714aa3496acSKumar Kartikeya Dwivedi 			break;
715f0c5941fSKumar Kartikeya Dwivedi 		case BPF_LIST_HEAD:
716f0c5941fSKumar Kartikeya Dwivedi 			if (WARN_ON_ONCE(rec->spin_lock_off < 0))
717f0c5941fSKumar Kartikeya Dwivedi 				continue;
718f0c5941fSKumar Kartikeya Dwivedi 			bpf_list_head_free(field, field_ptr, obj + rec->spin_lock_off);
719f0c5941fSKumar Kartikeya Dwivedi 			break;
7209c395c1bSDave Marchevsky 		case BPF_RB_ROOT:
7219c395c1bSDave Marchevsky 			if (WARN_ON_ONCE(rec->spin_lock_off < 0))
7229c395c1bSDave Marchevsky 				continue;
7239c395c1bSDave Marchevsky 			bpf_rb_root_free(field, field_ptr, obj + rec->spin_lock_off);
7249c395c1bSDave Marchevsky 			break;
7258ffa5cc1SKumar Kartikeya Dwivedi 		case BPF_LIST_NODE:
7269c395c1bSDave Marchevsky 		case BPF_RB_NODE:
727d54730b5SDave Marchevsky 		case BPF_REFCOUNT:
7288ffa5cc1SKumar Kartikeya Dwivedi 			break;
729aa3496acSKumar Kartikeya Dwivedi 		default:
730aa3496acSKumar Kartikeya Dwivedi 			WARN_ON_ONCE(1);
731aa3496acSKumar Kartikeya Dwivedi 			continue;
732aa3496acSKumar Kartikeya Dwivedi 		}
73314a324f6SKumar Kartikeya Dwivedi 	}
73414a324f6SKumar Kartikeya Dwivedi }
73514a324f6SKumar Kartikeya Dwivedi 
73699c55f7dSAlexei Starovoitov /* called from workqueue */
bpf_map_free_deferred(struct work_struct * work)73799c55f7dSAlexei Starovoitov static void bpf_map_free_deferred(struct work_struct *work)
73899c55f7dSAlexei Starovoitov {
73999c55f7dSAlexei Starovoitov 	struct bpf_map *map = container_of(work, struct bpf_map, work);
740d7f5ef65SKumar Kartikeya Dwivedi 	struct btf_record *rec = map->record;
74159e5791fSYonghong Song 	struct btf *btf = map->btf;
74299c55f7dSAlexei Starovoitov 
743afdb09c7SChenbo Feng 	security_bpf_map_free(map);
74448edc1f7SRoman Gushchin 	bpf_map_release_memcg(map);
745d7f5ef65SKumar Kartikeya Dwivedi 	/* implementation dependent freeing */
74699c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
747cd2a8079SDave Marchevsky 	/* Delay freeing of btf_record for maps, as map_free
748d7f5ef65SKumar Kartikeya Dwivedi 	 * callback usually needs access to them. It is better to do it here
749d7f5ef65SKumar Kartikeya Dwivedi 	 * than require each callback to do the free itself manually.
750d7f5ef65SKumar Kartikeya Dwivedi 	 *
751d7f5ef65SKumar Kartikeya Dwivedi 	 * Note that the btf_record stashed in map->inner_map_meta->record was
752d7f5ef65SKumar Kartikeya Dwivedi 	 * already freed using the map_free callback for map in map case which
753d7f5ef65SKumar Kartikeya Dwivedi 	 * eventually calls bpf_map_free_meta, since inner_map_meta is only a
754d7f5ef65SKumar Kartikeya Dwivedi 	 * template bpf_map struct used during verification.
755d7f5ef65SKumar Kartikeya Dwivedi 	 */
756d7f5ef65SKumar Kartikeya Dwivedi 	btf_record_free(rec);
75759e5791fSYonghong Song 	/* Delay freeing of btf for maps, as map_free callback may need
75859e5791fSYonghong Song 	 * struct_meta info which will be freed with btf_put().
75959e5791fSYonghong Song 	 */
76059e5791fSYonghong Song 	btf_put(btf);
76199c55f7dSAlexei Starovoitov }
76299c55f7dSAlexei Starovoitov 
bpf_map_put_uref(struct bpf_map * map)763c9da161cSDaniel Borkmann static void bpf_map_put_uref(struct bpf_map *map)
764c9da161cSDaniel Borkmann {
7651e0bd5a0SAndrii Nakryiko 	if (atomic64_dec_and_test(&map->usercnt)) {
766ba6b8de4SJohn Fastabend 		if (map->ops->map_release_uref)
767ba6b8de4SJohn Fastabend 			map->ops->map_release_uref(map);
768c9da161cSDaniel Borkmann 	}
769c9da161cSDaniel Borkmann }
770c9da161cSDaniel Borkmann 
bpf_map_free_in_work(struct bpf_map * map)77187667336SHou Tao static void bpf_map_free_in_work(struct bpf_map *map)
77287667336SHou Tao {
77387667336SHou Tao 	INIT_WORK(&map->work, bpf_map_free_deferred);
77487667336SHou Tao 	/* Avoid spawning kworkers, since they all might contend
77587667336SHou Tao 	 * for the same mutex like slab_mutex.
77687667336SHou Tao 	 */
77787667336SHou Tao 	queue_work(system_unbound_wq, &map->work);
77887667336SHou Tao }
77987667336SHou Tao 
bpf_map_free_rcu_gp(struct rcu_head * rcu)78087667336SHou Tao static void bpf_map_free_rcu_gp(struct rcu_head *rcu)
78187667336SHou Tao {
78287667336SHou Tao 	bpf_map_free_in_work(container_of(rcu, struct bpf_map, rcu));
78387667336SHou Tao }
78487667336SHou Tao 
bpf_map_free_mult_rcu_gp(struct rcu_head * rcu)78587667336SHou Tao static void bpf_map_free_mult_rcu_gp(struct rcu_head *rcu)
78687667336SHou Tao {
78787667336SHou Tao 	if (rcu_trace_implies_rcu_gp())
78887667336SHou Tao 		bpf_map_free_rcu_gp(rcu);
78987667336SHou Tao 	else
79087667336SHou Tao 		call_rcu(rcu, bpf_map_free_rcu_gp);
79187667336SHou Tao }
79287667336SHou Tao 
79399c55f7dSAlexei Starovoitov /* decrement map refcnt and schedule it for freeing via workqueue
794158e5e9eSTobias Klauser  * (underlying map implementation ops->map_free() might sleep)
79599c55f7dSAlexei Starovoitov  */
bpf_map_put(struct bpf_map * map)796158e5e9eSTobias Klauser void bpf_map_put(struct bpf_map *map)
79799c55f7dSAlexei Starovoitov {
7981e0bd5a0SAndrii Nakryiko 	if (atomic64_dec_and_test(&map->refcnt)) {
79934ad5580SMartin KaFai Lau 		/* bpf_map_free_id() must be called first */
800158e5e9eSTobias Klauser 		bpf_map_free_id(map);
80187667336SHou Tao 
802af66bfd3SHou Tao 		WARN_ON_ONCE(atomic64_read(&map->sleepable_refcnt));
80387667336SHou Tao 		if (READ_ONCE(map->free_after_mult_rcu_gp))
80487667336SHou Tao 			call_rcu_tasks_trace(&map->rcu, bpf_map_free_mult_rcu_gp);
805af66bfd3SHou Tao 		else if (READ_ONCE(map->free_after_rcu_gp))
806af66bfd3SHou Tao 			call_rcu(&map->rcu, bpf_map_free_rcu_gp);
80787667336SHou Tao 		else
80887667336SHou Tao 			bpf_map_free_in_work(map);
80999c55f7dSAlexei Starovoitov 	}
81099c55f7dSAlexei Starovoitov }
811630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_put);
812bd5f5f4eSMartin KaFai Lau 
bpf_map_put_with_uref(struct bpf_map * map)813c9da161cSDaniel Borkmann void bpf_map_put_with_uref(struct bpf_map *map)
814c9da161cSDaniel Borkmann {
815c9da161cSDaniel Borkmann 	bpf_map_put_uref(map);
816c9da161cSDaniel Borkmann 	bpf_map_put(map);
817c9da161cSDaniel Borkmann }
818c9da161cSDaniel Borkmann 
bpf_map_release(struct inode * inode,struct file * filp)81999c55f7dSAlexei Starovoitov static int bpf_map_release(struct inode *inode, struct file *filp)
82099c55f7dSAlexei Starovoitov {
82161d1b6a4SDaniel Borkmann 	struct bpf_map *map = filp->private_data;
82261d1b6a4SDaniel Borkmann 
82361d1b6a4SDaniel Borkmann 	if (map->ops->map_release)
82461d1b6a4SDaniel Borkmann 		map->ops->map_release(map, filp);
82561d1b6a4SDaniel Borkmann 
82661d1b6a4SDaniel Borkmann 	bpf_map_put_with_uref(map);
82799c55f7dSAlexei Starovoitov 	return 0;
82899c55f7dSAlexei Starovoitov }
82999c55f7dSAlexei Starovoitov 
map_get_sys_perms(struct bpf_map * map,struct fd f)83087df15deSDaniel Borkmann static fmode_t map_get_sys_perms(struct bpf_map *map, struct fd f)
83187df15deSDaniel Borkmann {
83287df15deSDaniel Borkmann 	fmode_t mode = f.file->f_mode;
83387df15deSDaniel Borkmann 
83487df15deSDaniel Borkmann 	/* Our file permissions may have been overridden by global
83587df15deSDaniel Borkmann 	 * map permissions facing syscall side.
83687df15deSDaniel Borkmann 	 */
83787df15deSDaniel Borkmann 	if (READ_ONCE(map->frozen))
83887df15deSDaniel Borkmann 		mode &= ~FMODE_CAN_WRITE;
83987df15deSDaniel Borkmann 	return mode;
84087df15deSDaniel Borkmann }
84187df15deSDaniel Borkmann 
842f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
84390a5527dSYafang Shao /* Show the memory usage of a bpf map */
bpf_map_memory_usage(const struct bpf_map * map)84490a5527dSYafang Shao static u64 bpf_map_memory_usage(const struct bpf_map *map)
84580ee81e0SRoman Gushchin {
84690a5527dSYafang Shao 	return map->ops->map_mem_usage(map);
84780ee81e0SRoman Gushchin }
84880ee81e0SRoman Gushchin 
bpf_map_show_fdinfo(struct seq_file * m,struct file * filp)849f99bf205SDaniel Borkmann static void bpf_map_show_fdinfo(struct seq_file *m, struct file *filp)
850f99bf205SDaniel Borkmann {
851f45d5b6cSToke Hoiland-Jorgensen 	struct bpf_map *map = filp->private_data;
8522beee5f5SDaniel Borkmann 	u32 type = 0, jited = 0;
85321116b70SDaniel Borkmann 
854f45d5b6cSToke Hoiland-Jorgensen 	if (map_type_contains_progs(map)) {
855f45d5b6cSToke Hoiland-Jorgensen 		spin_lock(&map->owner.lock);
856f45d5b6cSToke Hoiland-Jorgensen 		type  = map->owner.type;
857f45d5b6cSToke Hoiland-Jorgensen 		jited = map->owner.jited;
858f45d5b6cSToke Hoiland-Jorgensen 		spin_unlock(&map->owner.lock);
85921116b70SDaniel Borkmann 	}
860f99bf205SDaniel Borkmann 
861f99bf205SDaniel Borkmann 	seq_printf(m,
862f99bf205SDaniel Borkmann 		   "map_type:\t%u\n"
863f99bf205SDaniel Borkmann 		   "key_size:\t%u\n"
864f99bf205SDaniel Borkmann 		   "value_size:\t%u\n"
865322cea2fSDaniel Borkmann 		   "max_entries:\t%u\n"
86621116b70SDaniel Borkmann 		   "map_flags:\t%#x\n"
8679330986cSJoanne Koong 		   "map_extra:\t%#llx\n"
86890a5527dSYafang Shao 		   "memlock:\t%llu\n"
86987df15deSDaniel Borkmann 		   "map_id:\t%u\n"
87087df15deSDaniel Borkmann 		   "frozen:\t%u\n",
871f99bf205SDaniel Borkmann 		   map->map_type,
872f99bf205SDaniel Borkmann 		   map->key_size,
873f99bf205SDaniel Borkmann 		   map->value_size,
874322cea2fSDaniel Borkmann 		   map->max_entries,
87521116b70SDaniel Borkmann 		   map->map_flags,
8769330986cSJoanne Koong 		   (unsigned long long)map->map_extra,
87790a5527dSYafang Shao 		   bpf_map_memory_usage(map),
87887df15deSDaniel Borkmann 		   map->id,
87987df15deSDaniel Borkmann 		   READ_ONCE(map->frozen));
8802beee5f5SDaniel Borkmann 	if (type) {
8812beee5f5SDaniel Borkmann 		seq_printf(m, "owner_prog_type:\t%u\n", type);
8822beee5f5SDaniel Borkmann 		seq_printf(m, "owner_jited:\t%u\n", jited);
8839780c0abSDaniel Borkmann 	}
884f99bf205SDaniel Borkmann }
885f99bf205SDaniel Borkmann #endif
886f99bf205SDaniel Borkmann 
bpf_dummy_read(struct file * filp,char __user * buf,size_t siz,loff_t * ppos)8876e71b04aSChenbo Feng static ssize_t bpf_dummy_read(struct file *filp, char __user *buf, size_t siz,
8886e71b04aSChenbo Feng 			      loff_t *ppos)
8896e71b04aSChenbo Feng {
8906e71b04aSChenbo Feng 	/* We need this handler such that alloc_file() enables
8916e71b04aSChenbo Feng 	 * f_mode with FMODE_CAN_READ.
8926e71b04aSChenbo Feng 	 */
8936e71b04aSChenbo Feng 	return -EINVAL;
8946e71b04aSChenbo Feng }
8956e71b04aSChenbo Feng 
bpf_dummy_write(struct file * filp,const char __user * buf,size_t siz,loff_t * ppos)8966e71b04aSChenbo Feng static ssize_t bpf_dummy_write(struct file *filp, const char __user *buf,
8976e71b04aSChenbo Feng 			       size_t siz, loff_t *ppos)
8986e71b04aSChenbo Feng {
8996e71b04aSChenbo Feng 	/* We need this handler such that alloc_file() enables
9006e71b04aSChenbo Feng 	 * f_mode with FMODE_CAN_WRITE.
9016e71b04aSChenbo Feng 	 */
9026e71b04aSChenbo Feng 	return -EINVAL;
9036e71b04aSChenbo Feng }
9046e71b04aSChenbo Feng 
905fc970227SAndrii Nakryiko /* called for any extra memory-mapped regions (except initial) */
bpf_map_mmap_open(struct vm_area_struct * vma)906fc970227SAndrii Nakryiko static void bpf_map_mmap_open(struct vm_area_struct *vma)
907fc970227SAndrii Nakryiko {
908fc970227SAndrii Nakryiko 	struct bpf_map *map = vma->vm_file->private_data;
909fc970227SAndrii Nakryiko 
910353050beSDaniel Borkmann 	if (vma->vm_flags & VM_MAYWRITE)
911353050beSDaniel Borkmann 		bpf_map_write_active_inc(map);
912fc970227SAndrii Nakryiko }
913fc970227SAndrii Nakryiko 
914fc970227SAndrii Nakryiko /* called for all unmapped memory region (including initial) */
bpf_map_mmap_close(struct vm_area_struct * vma)915fc970227SAndrii Nakryiko static void bpf_map_mmap_close(struct vm_area_struct *vma)
916fc970227SAndrii Nakryiko {
917fc970227SAndrii Nakryiko 	struct bpf_map *map = vma->vm_file->private_data;
918fc970227SAndrii Nakryiko 
919353050beSDaniel Borkmann 	if (vma->vm_flags & VM_MAYWRITE)
920353050beSDaniel Borkmann 		bpf_map_write_active_dec(map);
921fc970227SAndrii Nakryiko }
922fc970227SAndrii Nakryiko 
923fc970227SAndrii Nakryiko static const struct vm_operations_struct bpf_map_default_vmops = {
924fc970227SAndrii Nakryiko 	.open		= bpf_map_mmap_open,
925fc970227SAndrii Nakryiko 	.close		= bpf_map_mmap_close,
926fc970227SAndrii Nakryiko };
927fc970227SAndrii Nakryiko 
bpf_map_mmap(struct file * filp,struct vm_area_struct * vma)928fc970227SAndrii Nakryiko static int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma)
929fc970227SAndrii Nakryiko {
930fc970227SAndrii Nakryiko 	struct bpf_map *map = filp->private_data;
931fc970227SAndrii Nakryiko 	int err;
932fc970227SAndrii Nakryiko 
933db559117SKumar Kartikeya Dwivedi 	if (!map->ops->map_mmap || !IS_ERR_OR_NULL(map->record))
934fc970227SAndrii Nakryiko 		return -ENOTSUPP;
935fc970227SAndrii Nakryiko 
936fc970227SAndrii Nakryiko 	if (!(vma->vm_flags & VM_SHARED))
937fc970227SAndrii Nakryiko 		return -EINVAL;
938fc970227SAndrii Nakryiko 
939fc970227SAndrii Nakryiko 	mutex_lock(&map->freeze_mutex);
940fc970227SAndrii Nakryiko 
941dfeb376dSAndrii Nakryiko 	if (vma->vm_flags & VM_WRITE) {
942dfeb376dSAndrii Nakryiko 		if (map->frozen) {
943fc970227SAndrii Nakryiko 			err = -EPERM;
944fc970227SAndrii Nakryiko 			goto out;
945fc970227SAndrii Nakryiko 		}
946dfeb376dSAndrii Nakryiko 		/* map is meant to be read-only, so do not allow mapping as
947dfeb376dSAndrii Nakryiko 		 * writable, because it's possible to leak a writable page
948dfeb376dSAndrii Nakryiko 		 * reference and allows user-space to still modify it after
949dfeb376dSAndrii Nakryiko 		 * freezing, while verifier will assume contents do not change
950dfeb376dSAndrii Nakryiko 		 */
951dfeb376dSAndrii Nakryiko 		if (map->map_flags & BPF_F_RDONLY_PROG) {
952dfeb376dSAndrii Nakryiko 			err = -EACCES;
953dfeb376dSAndrii Nakryiko 			goto out;
954dfeb376dSAndrii Nakryiko 		}
955dfeb376dSAndrii Nakryiko 	}
956fc970227SAndrii Nakryiko 
957fc970227SAndrii Nakryiko 	/* set default open/close callbacks */
958fc970227SAndrii Nakryiko 	vma->vm_ops = &bpf_map_default_vmops;
959fc970227SAndrii Nakryiko 	vma->vm_private_data = map;
9601c71222eSSuren Baghdasaryan 	vm_flags_clear(vma, VM_MAYEXEC);
9611f6cb19bSAndrii Nakryiko 	if (!(vma->vm_flags & VM_WRITE))
9621f6cb19bSAndrii Nakryiko 		/* disallow re-mapping with PROT_WRITE */
9631c71222eSSuren Baghdasaryan 		vm_flags_clear(vma, VM_MAYWRITE);
964fc970227SAndrii Nakryiko 
965fc970227SAndrii Nakryiko 	err = map->ops->map_mmap(map, vma);
966fc970227SAndrii Nakryiko 	if (err)
967fc970227SAndrii Nakryiko 		goto out;
968fc970227SAndrii Nakryiko 
9691f6cb19bSAndrii Nakryiko 	if (vma->vm_flags & VM_MAYWRITE)
970353050beSDaniel Borkmann 		bpf_map_write_active_inc(map);
971fc970227SAndrii Nakryiko out:
972fc970227SAndrii Nakryiko 	mutex_unlock(&map->freeze_mutex);
973fc970227SAndrii Nakryiko 	return err;
974fc970227SAndrii Nakryiko }
975fc970227SAndrii Nakryiko 
bpf_map_poll(struct file * filp,struct poll_table_struct * pts)976457f4436SAndrii Nakryiko static __poll_t bpf_map_poll(struct file *filp, struct poll_table_struct *pts)
977457f4436SAndrii Nakryiko {
978457f4436SAndrii Nakryiko 	struct bpf_map *map = filp->private_data;
979457f4436SAndrii Nakryiko 
980457f4436SAndrii Nakryiko 	if (map->ops->map_poll)
981457f4436SAndrii Nakryiko 		return map->ops->map_poll(map, filp, pts);
982457f4436SAndrii Nakryiko 
983457f4436SAndrii Nakryiko 	return EPOLLERR;
984457f4436SAndrii Nakryiko }
985457f4436SAndrii Nakryiko 
bpf_get_unmapped_area(struct file * filp,unsigned long addr,unsigned long len,unsigned long pgoff,unsigned long flags)986cf2c2e4aSAlexei Starovoitov static unsigned long bpf_get_unmapped_area(struct file *filp, unsigned long addr,
987cf2c2e4aSAlexei Starovoitov 					   unsigned long len, unsigned long pgoff,
988cf2c2e4aSAlexei Starovoitov 					   unsigned long flags)
989cf2c2e4aSAlexei Starovoitov {
990cf2c2e4aSAlexei Starovoitov 	struct bpf_map *map = filp->private_data;
991cf2c2e4aSAlexei Starovoitov 
992cf2c2e4aSAlexei Starovoitov 	if (map->ops->map_get_unmapped_area)
993cf2c2e4aSAlexei Starovoitov 		return map->ops->map_get_unmapped_area(filp, addr, len, pgoff, flags);
994cf2c2e4aSAlexei Starovoitov #ifdef CONFIG_MMU
995529ce23aSRick Edgecombe 	return mm_get_unmapped_area(current->mm, filp, addr, len, pgoff, flags);
996cf2c2e4aSAlexei Starovoitov #else
997cf2c2e4aSAlexei Starovoitov 	return addr;
998cf2c2e4aSAlexei Starovoitov #endif
999cf2c2e4aSAlexei Starovoitov }
1000cf2c2e4aSAlexei Starovoitov 
1001f66e448cSChenbo Feng const struct file_operations bpf_map_fops = {
1002f99bf205SDaniel Borkmann #ifdef CONFIG_PROC_FS
1003f99bf205SDaniel Borkmann 	.show_fdinfo	= bpf_map_show_fdinfo,
1004f99bf205SDaniel Borkmann #endif
100599c55f7dSAlexei Starovoitov 	.release	= bpf_map_release,
10066e71b04aSChenbo Feng 	.read		= bpf_dummy_read,
10076e71b04aSChenbo Feng 	.write		= bpf_dummy_write,
1008fc970227SAndrii Nakryiko 	.mmap		= bpf_map_mmap,
1009457f4436SAndrii Nakryiko 	.poll		= bpf_map_poll,
1010cf2c2e4aSAlexei Starovoitov 	.get_unmapped_area = bpf_get_unmapped_area,
101199c55f7dSAlexei Starovoitov };
101299c55f7dSAlexei Starovoitov 
bpf_map_new_fd(struct bpf_map * map,int flags)10136e71b04aSChenbo Feng int bpf_map_new_fd(struct bpf_map *map, int flags)
1014aa79781bSDaniel Borkmann {
1015afdb09c7SChenbo Feng 	int ret;
1016afdb09c7SChenbo Feng 
1017afdb09c7SChenbo Feng 	ret = security_bpf_map(map, OPEN_FMODE(flags));
1018afdb09c7SChenbo Feng 	if (ret < 0)
1019afdb09c7SChenbo Feng 		return ret;
1020afdb09c7SChenbo Feng 
1021aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-map", &bpf_map_fops, map,
10226e71b04aSChenbo Feng 				flags | O_CLOEXEC);
10236e71b04aSChenbo Feng }
10246e71b04aSChenbo Feng 
bpf_get_file_flag(int flags)10256e71b04aSChenbo Feng int bpf_get_file_flag(int flags)
10266e71b04aSChenbo Feng {
10276e71b04aSChenbo Feng 	if ((flags & BPF_F_RDONLY) && (flags & BPF_F_WRONLY))
10286e71b04aSChenbo Feng 		return -EINVAL;
10296e71b04aSChenbo Feng 	if (flags & BPF_F_RDONLY)
10306e71b04aSChenbo Feng 		return O_RDONLY;
10316e71b04aSChenbo Feng 	if (flags & BPF_F_WRONLY)
10326e71b04aSChenbo Feng 		return O_WRONLY;
10336e71b04aSChenbo Feng 	return O_RDWR;
1034aa79781bSDaniel Borkmann }
1035aa79781bSDaniel Borkmann 
103699c55f7dSAlexei Starovoitov /* helper macro to check that unused fields 'union bpf_attr' are zero */
103799c55f7dSAlexei Starovoitov #define CHECK_ATTR(CMD) \
103899c55f7dSAlexei Starovoitov 	memchr_inv((void *) &attr->CMD##_LAST_FIELD + \
103999c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD), 0, \
104099c55f7dSAlexei Starovoitov 		   sizeof(*attr) - \
104199c55f7dSAlexei Starovoitov 		   offsetof(union bpf_attr, CMD##_LAST_FIELD) - \
104299c55f7dSAlexei Starovoitov 		   sizeof(attr->CMD##_LAST_FIELD)) != NULL
104399c55f7dSAlexei Starovoitov 
10448e7ae251SMartin KaFai Lau /* dst and src must have at least "size" number of bytes.
10458e7ae251SMartin KaFai Lau  * Return strlen on success and < 0 on error.
1046cb4d2b3fSMartin KaFai Lau  */
bpf_obj_name_cpy(char * dst,const char * src,unsigned int size)10478e7ae251SMartin KaFai Lau int bpf_obj_name_cpy(char *dst, const char *src, unsigned int size)
1048cb4d2b3fSMartin KaFai Lau {
10498e7ae251SMartin KaFai Lau 	const char *end = src + size;
10508e7ae251SMartin KaFai Lau 	const char *orig_src = src;
1051cb4d2b3fSMartin KaFai Lau 
10528e7ae251SMartin KaFai Lau 	memset(dst, 0, size);
10533e0ddc4fSDaniel Borkmann 	/* Copy all isalnum(), '_' and '.' chars. */
1054cb4d2b3fSMartin KaFai Lau 	while (src < end && *src) {
10553e0ddc4fSDaniel Borkmann 		if (!isalnum(*src) &&
10563e0ddc4fSDaniel Borkmann 		    *src != '_' && *src != '.')
1057cb4d2b3fSMartin KaFai Lau 			return -EINVAL;
1058cb4d2b3fSMartin KaFai Lau 		*dst++ = *src++;
1059cb4d2b3fSMartin KaFai Lau 	}
1060cb4d2b3fSMartin KaFai Lau 
10618e7ae251SMartin KaFai Lau 	/* No '\0' found in "size" number of bytes */
1062cb4d2b3fSMartin KaFai Lau 	if (src == end)
1063cb4d2b3fSMartin KaFai Lau 		return -EINVAL;
1064cb4d2b3fSMartin KaFai Lau 
10658e7ae251SMartin KaFai Lau 	return src - orig_src;
1066cb4d2b3fSMartin KaFai Lau }
1067cb4d2b3fSMartin KaFai Lau 
map_check_no_btf(const struct bpf_map * map,const struct btf * btf,const struct btf_type * key_type,const struct btf_type * value_type)1068e8d2bec0SDaniel Borkmann int map_check_no_btf(const struct bpf_map *map,
10691b2b234bSRoman Gushchin 		     const struct btf *btf,
1070e8d2bec0SDaniel Borkmann 		     const struct btf_type *key_type,
1071e8d2bec0SDaniel Borkmann 		     const struct btf_type *value_type)
1072e8d2bec0SDaniel Borkmann {
1073e8d2bec0SDaniel Borkmann 	return -ENOTSUPP;
1074e8d2bec0SDaniel Borkmann }
1075e8d2bec0SDaniel Borkmann 
map_check_btf(struct bpf_map * map,struct bpf_token * token,const struct btf * btf,u32 btf_key_id,u32 btf_value_id)1076a177fc2bSAndrii Nakryiko static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
1077a177fc2bSAndrii Nakryiko 			 const struct btf *btf, u32 btf_key_id, u32 btf_value_id)
1078e8d2bec0SDaniel Borkmann {
1079e8d2bec0SDaniel Borkmann 	const struct btf_type *key_type, *value_type;
1080e8d2bec0SDaniel Borkmann 	u32 key_size, value_size;
1081e8d2bec0SDaniel Borkmann 	int ret = 0;
1082e8d2bec0SDaniel Borkmann 
10832824ecb7SDaniel Borkmann 	/* Some maps allow key to be unspecified. */
10842824ecb7SDaniel Borkmann 	if (btf_key_id) {
1085e8d2bec0SDaniel Borkmann 		key_type = btf_type_id_size(btf, &btf_key_id, &key_size);
1086e8d2bec0SDaniel Borkmann 		if (!key_type || key_size != map->key_size)
1087e8d2bec0SDaniel Borkmann 			return -EINVAL;
10882824ecb7SDaniel Borkmann 	} else {
10892824ecb7SDaniel Borkmann 		key_type = btf_type_by_id(btf, 0);
10902824ecb7SDaniel Borkmann 		if (!map->ops->map_check_btf)
10912824ecb7SDaniel Borkmann 			return -EINVAL;
10922824ecb7SDaniel Borkmann 	}
1093e8d2bec0SDaniel Borkmann 
1094e8d2bec0SDaniel Borkmann 	value_type = btf_type_id_size(btf, &btf_value_id, &value_size);
1095e8d2bec0SDaniel Borkmann 	if (!value_type || value_size != map->value_size)
1096e8d2bec0SDaniel Borkmann 		return -EINVAL;
1097e8d2bec0SDaniel Borkmann 
1098f0c5941fSKumar Kartikeya Dwivedi 	map->record = btf_parse_fields(btf, value_type,
10999c395c1bSDave Marchevsky 				       BPF_SPIN_LOCK | BPF_TIMER | BPF_KPTR | BPF_LIST_HEAD |
1100d56b63cfSBenjamin Tissoires 				       BPF_RB_ROOT | BPF_REFCOUNT | BPF_WORKQUEUE,
1101db559117SKumar Kartikeya Dwivedi 				       map->value_size);
1102aa3496acSKumar Kartikeya Dwivedi 	if (!IS_ERR_OR_NULL(map->record)) {
1103aa3496acSKumar Kartikeya Dwivedi 		int i;
1104aa3496acSKumar Kartikeya Dwivedi 
1105a177fc2bSAndrii Nakryiko 		if (!bpf_token_capable(token, CAP_BPF)) {
110661df10c7SKumar Kartikeya Dwivedi 			ret = -EPERM;
110761df10c7SKumar Kartikeya Dwivedi 			goto free_map_tab;
110861df10c7SKumar Kartikeya Dwivedi 		}
110961df10c7SKumar Kartikeya Dwivedi 		if (map->map_flags & (BPF_F_RDONLY_PROG | BPF_F_WRONLY_PROG)) {
111061df10c7SKumar Kartikeya Dwivedi 			ret = -EACCES;
111161df10c7SKumar Kartikeya Dwivedi 			goto free_map_tab;
111261df10c7SKumar Kartikeya Dwivedi 		}
1113aa3496acSKumar Kartikeya Dwivedi 		for (i = 0; i < sizeof(map->record->field_mask) * 8; i++) {
1114aa3496acSKumar Kartikeya Dwivedi 			switch (map->record->field_mask & (1 << i)) {
1115aa3496acSKumar Kartikeya Dwivedi 			case 0:
1116aa3496acSKumar Kartikeya Dwivedi 				continue;
1117db559117SKumar Kartikeya Dwivedi 			case BPF_SPIN_LOCK:
1118db559117SKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
1119db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY &&
1120db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_CGROUP_STORAGE &&
1121db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_SK_STORAGE &&
1122db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_INODE_STORAGE &&
1123db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_TASK_STORAGE &&
1124db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_CGRP_STORAGE) {
1125db559117SKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
1126db559117SKumar Kartikeya Dwivedi 					goto free_map_tab;
1127db559117SKumar Kartikeya Dwivedi 				}
1128db559117SKumar Kartikeya Dwivedi 				break;
1129db559117SKumar Kartikeya Dwivedi 			case BPF_TIMER:
1130246331e3SBenjamin Tissoires 			case BPF_WORKQUEUE:
1131db559117SKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
1132db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
1133db559117SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY) {
1134c237bfa5SKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
1135db559117SKumar Kartikeya Dwivedi 					goto free_map_tab;
1136db559117SKumar Kartikeya Dwivedi 				}
1137db559117SKumar Kartikeya Dwivedi 				break;
1138aa3496acSKumar Kartikeya Dwivedi 			case BPF_KPTR_UNREF:
1139aa3496acSKumar Kartikeya Dwivedi 			case BPF_KPTR_REF:
114055db92f4SYonghong Song 			case BPF_KPTR_PERCPU:
1141d54730b5SDave Marchevsky 			case BPF_REFCOUNT:
114261df10c7SKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
114365334e64SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_PERCPU_HASH &&
114461df10c7SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
114565334e64SKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_PERCPU_HASH &&
11466df4ea1fSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY &&
11479db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_PERCPU_ARRAY &&
11489db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_SK_STORAGE &&
11499db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_INODE_STORAGE &&
11509db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_TASK_STORAGE &&
11519db44fddSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_CGRP_STORAGE) {
115261df10c7SKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
115361df10c7SKumar Kartikeya Dwivedi 					goto free_map_tab;
115461df10c7SKumar Kartikeya Dwivedi 				}
1155aa3496acSKumar Kartikeya Dwivedi 				break;
1156f0c5941fSKumar Kartikeya Dwivedi 			case BPF_LIST_HEAD:
11579c395c1bSDave Marchevsky 			case BPF_RB_ROOT:
1158f0c5941fSKumar Kartikeya Dwivedi 				if (map->map_type != BPF_MAP_TYPE_HASH &&
1159f0c5941fSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_LRU_HASH &&
1160f0c5941fSKumar Kartikeya Dwivedi 				    map->map_type != BPF_MAP_TYPE_ARRAY) {
1161f0c5941fSKumar Kartikeya Dwivedi 					ret = -EOPNOTSUPP;
1162f0c5941fSKumar Kartikeya Dwivedi 					goto free_map_tab;
1163f0c5941fSKumar Kartikeya Dwivedi 				}
1164f0c5941fSKumar Kartikeya Dwivedi 				break;
1165aa3496acSKumar Kartikeya Dwivedi 			default:
1166aa3496acSKumar Kartikeya Dwivedi 				/* Fail if map_type checks are missing for a field type */
1167aa3496acSKumar Kartikeya Dwivedi 				ret = -EOPNOTSUPP;
1168aa3496acSKumar Kartikeya Dwivedi 				goto free_map_tab;
1169aa3496acSKumar Kartikeya Dwivedi 			}
1170aa3496acSKumar Kartikeya Dwivedi 		}
117161df10c7SKumar Kartikeya Dwivedi 	}
1172e8d2bec0SDaniel Borkmann 
1173865ce09aSKumar Kartikeya Dwivedi 	ret = btf_check_and_fixup_fields(btf, map->record);
1174865ce09aSKumar Kartikeya Dwivedi 	if (ret < 0)
1175865ce09aSKumar Kartikeya Dwivedi 		goto free_map_tab;
1176865ce09aSKumar Kartikeya Dwivedi 
117761df10c7SKumar Kartikeya Dwivedi 	if (map->ops->map_check_btf) {
117861df10c7SKumar Kartikeya Dwivedi 		ret = map->ops->map_check_btf(map, btf, key_type, value_type);
117961df10c7SKumar Kartikeya Dwivedi 		if (ret < 0)
118061df10c7SKumar Kartikeya Dwivedi 			goto free_map_tab;
118161df10c7SKumar Kartikeya Dwivedi 	}
118261df10c7SKumar Kartikeya Dwivedi 
118361df10c7SKumar Kartikeya Dwivedi 	return ret;
118461df10c7SKumar Kartikeya Dwivedi free_map_tab:
1185aa3496acSKumar Kartikeya Dwivedi 	bpf_map_free_record(map);
1186e8d2bec0SDaniel Borkmann 	return ret;
1187e8d2bec0SDaniel Borkmann }
1188e8d2bec0SDaniel Borkmann 
bpf_net_capable(void)1189ed1ad5a7SAndrii Nakryiko static bool bpf_net_capable(void)
1190ed1ad5a7SAndrii Nakryiko {
1191ed1ad5a7SAndrii Nakryiko 	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
1192ed1ad5a7SAndrii Nakryiko }
1193ed1ad5a7SAndrii Nakryiko 
1194a177fc2bSAndrii Nakryiko #define BPF_MAP_CREATE_LAST_FIELD map_token_fd
119599c55f7dSAlexei Starovoitov /* called via syscall */
map_create(union bpf_attr * attr)119699c55f7dSAlexei Starovoitov static int map_create(union bpf_attr *attr)
119799c55f7dSAlexei Starovoitov {
119822db4122SAndrii Nakryiko 	const struct bpf_map_ops *ops;
1199a177fc2bSAndrii Nakryiko 	struct bpf_token *token = NULL;
120096eabe7aSMartin KaFai Lau 	int numa_node = bpf_map_attr_numa_node(attr);
120122db4122SAndrii Nakryiko 	u32 map_type = attr->map_type;
120299c55f7dSAlexei Starovoitov 	struct bpf_map *map;
1203a177fc2bSAndrii Nakryiko 	bool token_flag;
12046e71b04aSChenbo Feng 	int f_flags;
120599c55f7dSAlexei Starovoitov 	int err;
120699c55f7dSAlexei Starovoitov 
120799c55f7dSAlexei Starovoitov 	err = CHECK_ATTR(BPF_MAP_CREATE);
120899c55f7dSAlexei Starovoitov 	if (err)
120999c55f7dSAlexei Starovoitov 		return -EINVAL;
121099c55f7dSAlexei Starovoitov 
1211a177fc2bSAndrii Nakryiko 	/* check BPF_F_TOKEN_FD flag, remember if it's set, and then clear it
1212a177fc2bSAndrii Nakryiko 	 * to avoid per-map type checks tripping on unknown flag
1213a177fc2bSAndrii Nakryiko 	 */
1214a177fc2bSAndrii Nakryiko 	token_flag = attr->map_flags & BPF_F_TOKEN_FD;
1215a177fc2bSAndrii Nakryiko 	attr->map_flags &= ~BPF_F_TOKEN_FD;
1216a177fc2bSAndrii Nakryiko 
121785d33df3SMartin KaFai Lau 	if (attr->btf_vmlinux_value_type_id) {
121885d33df3SMartin KaFai Lau 		if (attr->map_type != BPF_MAP_TYPE_STRUCT_OPS ||
121985d33df3SMartin KaFai Lau 		    attr->btf_key_type_id || attr->btf_value_type_id)
122085d33df3SMartin KaFai Lau 			return -EINVAL;
122185d33df3SMartin KaFai Lau 	} else if (attr->btf_key_type_id && !attr->btf_value_type_id) {
122285d33df3SMartin KaFai Lau 		return -EINVAL;
122385d33df3SMartin KaFai Lau 	}
122485d33df3SMartin KaFai Lau 
12259330986cSJoanne Koong 	if (attr->map_type != BPF_MAP_TYPE_BLOOM_FILTER &&
122631746031SAlexei Starovoitov 	    attr->map_type != BPF_MAP_TYPE_ARENA &&
12279330986cSJoanne Koong 	    attr->map_extra != 0)
12289330986cSJoanne Koong 		return -EINVAL;
12299330986cSJoanne Koong 
12306e71b04aSChenbo Feng 	f_flags = bpf_get_file_flag(attr->map_flags);
12316e71b04aSChenbo Feng 	if (f_flags < 0)
12326e71b04aSChenbo Feng 		return f_flags;
12336e71b04aSChenbo Feng 
123496eabe7aSMartin KaFai Lau 	if (numa_node != NUMA_NO_NODE &&
123596e5ae4eSEric Dumazet 	    ((unsigned int)numa_node >= nr_node_ids ||
123696e5ae4eSEric Dumazet 	     !node_online(numa_node)))
123796eabe7aSMartin KaFai Lau 		return -EINVAL;
123896eabe7aSMartin KaFai Lau 
123999c55f7dSAlexei Starovoitov 	/* find map type and init map: hashtable vs rbtree vs bloom vs ... */
124022db4122SAndrii Nakryiko 	map_type = attr->map_type;
124122db4122SAndrii Nakryiko 	if (map_type >= ARRAY_SIZE(bpf_map_types))
124222db4122SAndrii Nakryiko 		return -EINVAL;
124322db4122SAndrii Nakryiko 	map_type = array_index_nospec(map_type, ARRAY_SIZE(bpf_map_types));
124422db4122SAndrii Nakryiko 	ops = bpf_map_types[map_type];
124522db4122SAndrii Nakryiko 	if (!ops)
124622db4122SAndrii Nakryiko 		return -EINVAL;
124722db4122SAndrii Nakryiko 
124822db4122SAndrii Nakryiko 	if (ops->map_alloc_check) {
124922db4122SAndrii Nakryiko 		err = ops->map_alloc_check(attr);
125022db4122SAndrii Nakryiko 		if (err)
125122db4122SAndrii Nakryiko 			return err;
125222db4122SAndrii Nakryiko 	}
125322db4122SAndrii Nakryiko 	if (attr->map_ifindex)
125422db4122SAndrii Nakryiko 		ops = &bpf_map_offload_ops;
125522db4122SAndrii Nakryiko 	if (!ops->map_mem_usage)
125622db4122SAndrii Nakryiko 		return -EINVAL;
125722db4122SAndrii Nakryiko 
1258a177fc2bSAndrii Nakryiko 	if (token_flag) {
1259a177fc2bSAndrii Nakryiko 		token = bpf_token_get_from_fd(attr->map_token_fd);
1260a177fc2bSAndrii Nakryiko 		if (IS_ERR(token))
1261a177fc2bSAndrii Nakryiko 			return PTR_ERR(token);
1262a177fc2bSAndrii Nakryiko 
1263a177fc2bSAndrii Nakryiko 		/* if current token doesn't grant map creation permissions,
1264a177fc2bSAndrii Nakryiko 		 * then we can't use this token, so ignore it and rely on
1265a177fc2bSAndrii Nakryiko 		 * system-wide capabilities checks
1266a177fc2bSAndrii Nakryiko 		 */
1267a177fc2bSAndrii Nakryiko 		if (!bpf_token_allow_cmd(token, BPF_MAP_CREATE) ||
1268a177fc2bSAndrii Nakryiko 		    !bpf_token_allow_map_type(token, attr->map_type)) {
1269a177fc2bSAndrii Nakryiko 			bpf_token_put(token);
1270a177fc2bSAndrii Nakryiko 			token = NULL;
1271a177fc2bSAndrii Nakryiko 		}
1272a177fc2bSAndrii Nakryiko 	}
1273a177fc2bSAndrii Nakryiko 
1274a177fc2bSAndrii Nakryiko 	err = -EPERM;
1275a177fc2bSAndrii Nakryiko 
12761d28635aSAndrii Nakryiko 	/* Intent here is for unprivileged_bpf_disabled to block BPF map
12771d28635aSAndrii Nakryiko 	 * creation for unprivileged users; other actions depend
12781d28635aSAndrii Nakryiko 	 * on fd availability and access to bpffs, so are dependent on
12791d28635aSAndrii Nakryiko 	 * object creation success. Even with unprivileged BPF disabled,
12801d28635aSAndrii Nakryiko 	 * capability checks are still carried out.
12811d28635aSAndrii Nakryiko 	 */
1282a177fc2bSAndrii Nakryiko 	if (sysctl_unprivileged_bpf_disabled && !bpf_token_capable(token, CAP_BPF))
1283a177fc2bSAndrii Nakryiko 		goto put_token;
12841d28635aSAndrii Nakryiko 
12856c3eba1cSAndrii Nakryiko 	/* check privileged map type permissions */
12866c3eba1cSAndrii Nakryiko 	switch (map_type) {
12876c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_ARRAY:
12886c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PERCPU_ARRAY:
12896c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PROG_ARRAY:
12906c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
12916c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_CGROUP_ARRAY:
12926c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_ARRAY_OF_MAPS:
12936c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_HASH:
12946c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PERCPU_HASH:
12956c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_HASH_OF_MAPS:
12966c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_RINGBUF:
12976c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_USER_RINGBUF:
12986c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_CGROUP_STORAGE:
12996c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE:
13006c3eba1cSAndrii Nakryiko 		/* unprivileged */
13016c3eba1cSAndrii Nakryiko 		break;
13026c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_SK_STORAGE:
13036c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_INODE_STORAGE:
13046c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_TASK_STORAGE:
13056c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_CGRP_STORAGE:
13066c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_BLOOM_FILTER:
13076c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_LPM_TRIE:
13086c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY:
13096c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_STACK_TRACE:
13106c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_QUEUE:
13116c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_STACK:
13126c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_LRU_HASH:
13136c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_LRU_PERCPU_HASH:
13146c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_STRUCT_OPS:
13156c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_CPUMAP:
131631746031SAlexei Starovoitov 	case BPF_MAP_TYPE_ARENA:
1317a177fc2bSAndrii Nakryiko 		if (!bpf_token_capable(token, CAP_BPF))
1318a177fc2bSAndrii Nakryiko 			goto put_token;
13196c3eba1cSAndrii Nakryiko 		break;
13206c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_SOCKMAP:
13216c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_SOCKHASH:
13226c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_DEVMAP:
13236c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_DEVMAP_HASH:
13246c3eba1cSAndrii Nakryiko 	case BPF_MAP_TYPE_XSKMAP:
1325a177fc2bSAndrii Nakryiko 		if (!bpf_token_capable(token, CAP_NET_ADMIN))
1326a177fc2bSAndrii Nakryiko 			goto put_token;
13276c3eba1cSAndrii Nakryiko 		break;
13286c3eba1cSAndrii Nakryiko 	default:
13296c3eba1cSAndrii Nakryiko 		WARN(1, "unsupported map type %d", map_type);
1330a177fc2bSAndrii Nakryiko 		goto put_token;
13316c3eba1cSAndrii Nakryiko 	}
13326c3eba1cSAndrii Nakryiko 
133322db4122SAndrii Nakryiko 	map = ops->map_alloc(attr);
1334a177fc2bSAndrii Nakryiko 	if (IS_ERR(map)) {
1335a177fc2bSAndrii Nakryiko 		err = PTR_ERR(map);
1336a177fc2bSAndrii Nakryiko 		goto put_token;
1337a177fc2bSAndrii Nakryiko 	}
133822db4122SAndrii Nakryiko 	map->ops = ops;
133922db4122SAndrii Nakryiko 	map->map_type = map_type;
134099c55f7dSAlexei Starovoitov 
13418e7ae251SMartin KaFai Lau 	err = bpf_obj_name_cpy(map->name, attr->map_name,
13428e7ae251SMartin KaFai Lau 			       sizeof(attr->map_name));
13438e7ae251SMartin KaFai Lau 	if (err < 0)
1344b936ca64SRoman Gushchin 		goto free_map;
1345ad5b177bSMartin KaFai Lau 
13461e0bd5a0SAndrii Nakryiko 	atomic64_set(&map->refcnt, 1);
13471e0bd5a0SAndrii Nakryiko 	atomic64_set(&map->usercnt, 1);
1348fc970227SAndrii Nakryiko 	mutex_init(&map->freeze_mutex);
1349f45d5b6cSToke Hoiland-Jorgensen 	spin_lock_init(&map->owner.lock);
135099c55f7dSAlexei Starovoitov 
135185d33df3SMartin KaFai Lau 	if (attr->btf_key_type_id || attr->btf_value_type_id ||
135285d33df3SMartin KaFai Lau 	    /* Even the map's value is a kernel's struct,
135385d33df3SMartin KaFai Lau 	     * the bpf_prog.o must have BTF to begin with
135485d33df3SMartin KaFai Lau 	     * to figure out the corresponding kernel's
135585d33df3SMartin KaFai Lau 	     * counter part.  Thus, attr->btf_fd has
135685d33df3SMartin KaFai Lau 	     * to be valid also.
135785d33df3SMartin KaFai Lau 	     */
135885d33df3SMartin KaFai Lau 	    attr->btf_vmlinux_value_type_id) {
1359a26ca7c9SMartin KaFai Lau 		struct btf *btf;
1360a26ca7c9SMartin KaFai Lau 
1361a26ca7c9SMartin KaFai Lau 		btf = btf_get_by_fd(attr->btf_fd);
1362a26ca7c9SMartin KaFai Lau 		if (IS_ERR(btf)) {
1363a26ca7c9SMartin KaFai Lau 			err = PTR_ERR(btf);
1364b936ca64SRoman Gushchin 			goto free_map;
1365a26ca7c9SMartin KaFai Lau 		}
1366350a5c4dSAlexei Starovoitov 		if (btf_is_kernel(btf)) {
1367350a5c4dSAlexei Starovoitov 			btf_put(btf);
1368350a5c4dSAlexei Starovoitov 			err = -EACCES;
1369350a5c4dSAlexei Starovoitov 			goto free_map;
1370350a5c4dSAlexei Starovoitov 		}
137185d33df3SMartin KaFai Lau 		map->btf = btf;
1372a26ca7c9SMartin KaFai Lau 
137385d33df3SMartin KaFai Lau 		if (attr->btf_value_type_id) {
1374a177fc2bSAndrii Nakryiko 			err = map_check_btf(map, token, btf, attr->btf_key_type_id,
13759b2cf328SMartin KaFai Lau 					    attr->btf_value_type_id);
137685d33df3SMartin KaFai Lau 			if (err)
1377b936ca64SRoman Gushchin 				goto free_map;
1378a26ca7c9SMartin KaFai Lau 		}
1379a26ca7c9SMartin KaFai Lau 
13809b2cf328SMartin KaFai Lau 		map->btf_key_type_id = attr->btf_key_type_id;
13819b2cf328SMartin KaFai Lau 		map->btf_value_type_id = attr->btf_value_type_id;
138285d33df3SMartin KaFai Lau 		map->btf_vmlinux_value_type_id =
138385d33df3SMartin KaFai Lau 			attr->btf_vmlinux_value_type_id;
1384a26ca7c9SMartin KaFai Lau 	}
1385a26ca7c9SMartin KaFai Lau 
1386a2431c7eSAndrii Nakryiko 	err = security_bpf_map_create(map, attr, token);
13874d7d7f69SKumar Kartikeya Dwivedi 	if (err)
1388a2431c7eSAndrii Nakryiko 		goto free_map_sec;
13894d7d7f69SKumar Kartikeya Dwivedi 
1390f3f1c054SMartin KaFai Lau 	err = bpf_map_alloc_id(map);
1391f3f1c054SMartin KaFai Lau 	if (err)
1392b936ca64SRoman Gushchin 		goto free_map_sec;
1393f3f1c054SMartin KaFai Lau 
139448edc1f7SRoman Gushchin 	bpf_map_save_memcg(map);
1395a177fc2bSAndrii Nakryiko 	bpf_token_put(token);
139648edc1f7SRoman Gushchin 
13976e71b04aSChenbo Feng 	err = bpf_map_new_fd(map, f_flags);
1398bd5f5f4eSMartin KaFai Lau 	if (err < 0) {
1399bd5f5f4eSMartin KaFai Lau 		/* failed to allocate fd.
1400352d20d6SPeng Sun 		 * bpf_map_put_with_uref() is needed because the above
1401bd5f5f4eSMartin KaFai Lau 		 * bpf_map_alloc_id() has published the map
1402bd5f5f4eSMartin KaFai Lau 		 * to the userspace and the userspace may
1403bd5f5f4eSMartin KaFai Lau 		 * have refcnt-ed it through BPF_MAP_GET_FD_BY_ID.
1404bd5f5f4eSMartin KaFai Lau 		 */
1405352d20d6SPeng Sun 		bpf_map_put_with_uref(map);
1406bd5f5f4eSMartin KaFai Lau 		return err;
1407bd5f5f4eSMartin KaFai Lau 	}
140899c55f7dSAlexei Starovoitov 
140999c55f7dSAlexei Starovoitov 	return err;
141099c55f7dSAlexei Starovoitov 
1411afdb09c7SChenbo Feng free_map_sec:
1412afdb09c7SChenbo Feng 	security_bpf_map_free(map);
1413b936ca64SRoman Gushchin free_map:
1414a26ca7c9SMartin KaFai Lau 	btf_put(map->btf);
141599c55f7dSAlexei Starovoitov 	map->ops->map_free(map);
1416a177fc2bSAndrii Nakryiko put_token:
1417a177fc2bSAndrii Nakryiko 	bpf_token_put(token);
141899c55f7dSAlexei Starovoitov 	return err;
141999c55f7dSAlexei Starovoitov }
142099c55f7dSAlexei Starovoitov 
1421db20fd2bSAlexei Starovoitov /* if error is returned, fd is released.
1422db20fd2bSAlexei Starovoitov  * On success caller should complete fd access with matching fdput()
1423db20fd2bSAlexei Starovoitov  */
__bpf_map_get(struct fd f)1424c2101297SDaniel Borkmann struct bpf_map *__bpf_map_get(struct fd f)
1425db20fd2bSAlexei Starovoitov {
1426db20fd2bSAlexei Starovoitov 	if (!f.file)
1427db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EBADF);
1428db20fd2bSAlexei Starovoitov 	if (f.file->f_op != &bpf_map_fops) {
1429db20fd2bSAlexei Starovoitov 		fdput(f);
1430db20fd2bSAlexei Starovoitov 		return ERR_PTR(-EINVAL);
1431db20fd2bSAlexei Starovoitov 	}
1432db20fd2bSAlexei Starovoitov 
1433c2101297SDaniel Borkmann 	return f.file->private_data;
1434c2101297SDaniel Borkmann }
1435c2101297SDaniel Borkmann 
bpf_map_inc(struct bpf_map * map)14361e0bd5a0SAndrii Nakryiko void bpf_map_inc(struct bpf_map *map)
1437c9da161cSDaniel Borkmann {
14381e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->refcnt);
1439c9da161cSDaniel Borkmann }
1440630a4d38SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_map_inc);
1441c9da161cSDaniel Borkmann 
bpf_map_inc_with_uref(struct bpf_map * map)14421e0bd5a0SAndrii Nakryiko void bpf_map_inc_with_uref(struct bpf_map *map)
14431e0bd5a0SAndrii Nakryiko {
14441e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->refcnt);
14451e0bd5a0SAndrii Nakryiko 	atomic64_inc(&map->usercnt);
14461e0bd5a0SAndrii Nakryiko }
14471e0bd5a0SAndrii Nakryiko EXPORT_SYMBOL_GPL(bpf_map_inc_with_uref);
14481e0bd5a0SAndrii Nakryiko 
bpf_map_get(u32 ufd)14491ed4d924SMartin KaFai Lau struct bpf_map *bpf_map_get(u32 ufd)
14501ed4d924SMartin KaFai Lau {
14511ed4d924SMartin KaFai Lau 	struct fd f = fdget(ufd);
14521ed4d924SMartin KaFai Lau 	struct bpf_map *map;
14531ed4d924SMartin KaFai Lau 
14541ed4d924SMartin KaFai Lau 	map = __bpf_map_get(f);
14551ed4d924SMartin KaFai Lau 	if (IS_ERR(map))
14561ed4d924SMartin KaFai Lau 		return map;
14571ed4d924SMartin KaFai Lau 
14581ed4d924SMartin KaFai Lau 	bpf_map_inc(map);
14591ed4d924SMartin KaFai Lau 	fdput(f);
14601ed4d924SMartin KaFai Lau 
14611ed4d924SMartin KaFai Lau 	return map;
14621ed4d924SMartin KaFai Lau }
1463b1d18a75SAlexei Starovoitov EXPORT_SYMBOL(bpf_map_get);
14641ed4d924SMartin KaFai Lau 
bpf_map_get_with_uref(u32 ufd)1465c9da161cSDaniel Borkmann struct bpf_map *bpf_map_get_with_uref(u32 ufd)
1466c2101297SDaniel Borkmann {
1467c2101297SDaniel Borkmann 	struct fd f = fdget(ufd);
1468c2101297SDaniel Borkmann 	struct bpf_map *map;
1469c2101297SDaniel Borkmann 
1470c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1471c2101297SDaniel Borkmann 	if (IS_ERR(map))
1472c2101297SDaniel Borkmann 		return map;
1473c2101297SDaniel Borkmann 
14741e0bd5a0SAndrii Nakryiko 	bpf_map_inc_with_uref(map);
1475c2101297SDaniel Borkmann 	fdput(f);
1476db20fd2bSAlexei Starovoitov 
1477db20fd2bSAlexei Starovoitov 	return map;
1478db20fd2bSAlexei Starovoitov }
1479db20fd2bSAlexei Starovoitov 
1480b671c206SKui-Feng Lee /* map_idr_lock should have been held or the map should have been
1481b671c206SKui-Feng Lee  * protected by rcu read lock.
1482b671c206SKui-Feng Lee  */
__bpf_map_inc_not_zero(struct bpf_map * map,bool uref)1483b671c206SKui-Feng Lee struct bpf_map *__bpf_map_inc_not_zero(struct bpf_map *map, bool uref)
1484bd5f5f4eSMartin KaFai Lau {
1485bd5f5f4eSMartin KaFai Lau 	int refold;
1486bd5f5f4eSMartin KaFai Lau 
14871e0bd5a0SAndrii Nakryiko 	refold = atomic64_fetch_add_unless(&map->refcnt, 1, 0);
1488bd5f5f4eSMartin KaFai Lau 	if (!refold)
1489bd5f5f4eSMartin KaFai Lau 		return ERR_PTR(-ENOENT);
1490bd5f5f4eSMartin KaFai Lau 	if (uref)
14911e0bd5a0SAndrii Nakryiko 		atomic64_inc(&map->usercnt);
1492bd5f5f4eSMartin KaFai Lau 
1493bd5f5f4eSMartin KaFai Lau 	return map;
1494bd5f5f4eSMartin KaFai Lau }
1495bd5f5f4eSMartin KaFai Lau 
bpf_map_inc_not_zero(struct bpf_map * map)14961e0bd5a0SAndrii Nakryiko struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map)
1497b0e4701cSStanislav Fomichev {
1498b0e4701cSStanislav Fomichev 	spin_lock_bh(&map_idr_lock);
14991e0bd5a0SAndrii Nakryiko 	map = __bpf_map_inc_not_zero(map, false);
1500b0e4701cSStanislav Fomichev 	spin_unlock_bh(&map_idr_lock);
1501b0e4701cSStanislav Fomichev 
1502b0e4701cSStanislav Fomichev 	return map;
1503b0e4701cSStanislav Fomichev }
1504b0e4701cSStanislav Fomichev EXPORT_SYMBOL_GPL(bpf_map_inc_not_zero);
1505b0e4701cSStanislav Fomichev 
bpf_stackmap_copy(struct bpf_map * map,void * key,void * value)1506b8cdc051SAlexei Starovoitov int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
1507b8cdc051SAlexei Starovoitov {
1508b8cdc051SAlexei Starovoitov 	return -ENOTSUPP;
1509b8cdc051SAlexei Starovoitov }
1510b8cdc051SAlexei Starovoitov 
__bpf_copy_key(void __user * ukey,u64 key_size)1511c9d29f46SMauricio Vasquez B static void *__bpf_copy_key(void __user *ukey, u64 key_size)
1512c9d29f46SMauricio Vasquez B {
1513c9d29f46SMauricio Vasquez B 	if (key_size)
151444779a4bSStanislav Fomichev 		return vmemdup_user(ukey, key_size);
1515c9d29f46SMauricio Vasquez B 
1516c9d29f46SMauricio Vasquez B 	if (ukey)
1517c9d29f46SMauricio Vasquez B 		return ERR_PTR(-EINVAL);
1518c9d29f46SMauricio Vasquez B 
1519c9d29f46SMauricio Vasquez B 	return NULL;
1520c9d29f46SMauricio Vasquez B }
1521c9d29f46SMauricio Vasquez B 
___bpf_copy_key(bpfptr_t ukey,u64 key_size)1522af2ac3e1SAlexei Starovoitov static void *___bpf_copy_key(bpfptr_t ukey, u64 key_size)
1523af2ac3e1SAlexei Starovoitov {
1524af2ac3e1SAlexei Starovoitov 	if (key_size)
152544779a4bSStanislav Fomichev 		return kvmemdup_bpfptr(ukey, key_size);
1526af2ac3e1SAlexei Starovoitov 
1527af2ac3e1SAlexei Starovoitov 	if (!bpfptr_is_null(ukey))
1528af2ac3e1SAlexei Starovoitov 		return ERR_PTR(-EINVAL);
1529af2ac3e1SAlexei Starovoitov 
1530af2ac3e1SAlexei Starovoitov 	return NULL;
1531af2ac3e1SAlexei Starovoitov }
1532af2ac3e1SAlexei Starovoitov 
1533db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
153496049f3aSAlexei Starovoitov #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD flags
1535db20fd2bSAlexei Starovoitov 
map_lookup_elem(union bpf_attr * attr)1536db20fd2bSAlexei Starovoitov static int map_lookup_elem(union bpf_attr *attr)
1537db20fd2bSAlexei Starovoitov {
1538535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
1539535e7b4bSMickaël Salaün 	void __user *uvalue = u64_to_user_ptr(attr->value);
1540db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1541db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
154215c14a3dSBrian Vazquez 	void *key, *value;
154315a07b33SAlexei Starovoitov 	u32 value_size;
1544592867bfSDaniel Borkmann 	struct fd f;
1545db20fd2bSAlexei Starovoitov 	int err;
1546db20fd2bSAlexei Starovoitov 
1547db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
1548db20fd2bSAlexei Starovoitov 		return -EINVAL;
1549db20fd2bSAlexei Starovoitov 
155096049f3aSAlexei Starovoitov 	if (attr->flags & ~BPF_F_LOCK)
155196049f3aSAlexei Starovoitov 		return -EINVAL;
155296049f3aSAlexei Starovoitov 
1553592867bfSDaniel Borkmann 	f = fdget(ufd);
1554c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1555db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1556db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
155787df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
15586e71b04aSChenbo Feng 		err = -EPERM;
15596e71b04aSChenbo Feng 		goto err_put;
15606e71b04aSChenbo Feng 	}
15616e71b04aSChenbo Feng 
156296049f3aSAlexei Starovoitov 	if ((attr->flags & BPF_F_LOCK) &&
1563db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
156496049f3aSAlexei Starovoitov 		err = -EINVAL;
156596049f3aSAlexei Starovoitov 		goto err_put;
156696049f3aSAlexei Starovoitov 	}
156796049f3aSAlexei Starovoitov 
1568c9d29f46SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
1569e4448ed8SAl Viro 	if (IS_ERR(key)) {
1570e4448ed8SAl Viro 		err = PTR_ERR(key);
1571db20fd2bSAlexei Starovoitov 		goto err_put;
1572e4448ed8SAl Viro 	}
1573db20fd2bSAlexei Starovoitov 
157415c14a3dSBrian Vazquez 	value_size = bpf_map_value_size(map);
157515a07b33SAlexei Starovoitov 
15768ebe667cSAlexei Starovoitov 	err = -ENOMEM;
1577f0dce1d9SStanislav Fomichev 	value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN);
1578db20fd2bSAlexei Starovoitov 	if (!value)
15798ebe667cSAlexei Starovoitov 		goto free_key;
15808ebe667cSAlexei Starovoitov 
15819330986cSJoanne Koong 	if (map->map_type == BPF_MAP_TYPE_BLOOM_FILTER) {
15829330986cSJoanne Koong 		if (copy_from_user(value, uvalue, value_size))
15839330986cSJoanne Koong 			err = -EFAULT;
15849330986cSJoanne Koong 		else
15859330986cSJoanne Koong 			err = bpf_map_copy_value(map, key, value, attr->flags);
15869330986cSJoanne Koong 		goto free_value;
15879330986cSJoanne Koong 	}
15889330986cSJoanne Koong 
158915c14a3dSBrian Vazquez 	err = bpf_map_copy_value(map, key, value, attr->flags);
159015a07b33SAlexei Starovoitov 	if (err)
15918ebe667cSAlexei Starovoitov 		goto free_value;
1592db20fd2bSAlexei Starovoitov 
1593db20fd2bSAlexei Starovoitov 	err = -EFAULT;
159415a07b33SAlexei Starovoitov 	if (copy_to_user(uvalue, value, value_size) != 0)
15958ebe667cSAlexei Starovoitov 		goto free_value;
1596db20fd2bSAlexei Starovoitov 
1597db20fd2bSAlexei Starovoitov 	err = 0;
1598db20fd2bSAlexei Starovoitov 
15998ebe667cSAlexei Starovoitov free_value:
1600f0dce1d9SStanislav Fomichev 	kvfree(value);
1601db20fd2bSAlexei Starovoitov free_key:
160244779a4bSStanislav Fomichev 	kvfree(key);
1603db20fd2bSAlexei Starovoitov err_put:
1604db20fd2bSAlexei Starovoitov 	fdput(f);
1605db20fd2bSAlexei Starovoitov 	return err;
1606db20fd2bSAlexei Starovoitov }
1607db20fd2bSAlexei Starovoitov 
16081ae80cf3SDaniel Colascione 
16093274f520SAlexei Starovoitov #define BPF_MAP_UPDATE_ELEM_LAST_FIELD flags
1610db20fd2bSAlexei Starovoitov 
map_update_elem(union bpf_attr * attr,bpfptr_t uattr)1611af2ac3e1SAlexei Starovoitov static int map_update_elem(union bpf_attr *attr, bpfptr_t uattr)
1612db20fd2bSAlexei Starovoitov {
1613af2ac3e1SAlexei Starovoitov 	bpfptr_t ukey = make_bpfptr(attr->key, uattr.is_kernel);
1614af2ac3e1SAlexei Starovoitov 	bpfptr_t uvalue = make_bpfptr(attr->value, uattr.is_kernel);
1615db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1616db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1617db20fd2bSAlexei Starovoitov 	void *key, *value;
161815a07b33SAlexei Starovoitov 	u32 value_size;
1619592867bfSDaniel Borkmann 	struct fd f;
1620db20fd2bSAlexei Starovoitov 	int err;
1621db20fd2bSAlexei Starovoitov 
1622db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM))
1623db20fd2bSAlexei Starovoitov 		return -EINVAL;
1624db20fd2bSAlexei Starovoitov 
1625592867bfSDaniel Borkmann 	f = fdget(ufd);
1626c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1627db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1628db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
1629353050beSDaniel Borkmann 	bpf_map_write_active_inc(map);
163087df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
16316e71b04aSChenbo Feng 		err = -EPERM;
16326e71b04aSChenbo Feng 		goto err_put;
16336e71b04aSChenbo Feng 	}
16346e71b04aSChenbo Feng 
163596049f3aSAlexei Starovoitov 	if ((attr->flags & BPF_F_LOCK) &&
1636db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
163796049f3aSAlexei Starovoitov 		err = -EINVAL;
163896049f3aSAlexei Starovoitov 		goto err_put;
163996049f3aSAlexei Starovoitov 	}
164096049f3aSAlexei Starovoitov 
1641af2ac3e1SAlexei Starovoitov 	key = ___bpf_copy_key(ukey, map->key_size);
1642e4448ed8SAl Viro 	if (IS_ERR(key)) {
1643e4448ed8SAl Viro 		err = PTR_ERR(key);
1644db20fd2bSAlexei Starovoitov 		goto err_put;
1645e4448ed8SAl Viro 	}
1646db20fd2bSAlexei Starovoitov 
1647f0dce1d9SStanislav Fomichev 	value_size = bpf_map_value_size(map);
1648a02c118eSWang Yufen 	value = kvmemdup_bpfptr(uvalue, value_size);
1649a02c118eSWang Yufen 	if (IS_ERR(value)) {
1650a02c118eSWang Yufen 		err = PTR_ERR(value);
1651db20fd2bSAlexei Starovoitov 		goto free_key;
1652a02c118eSWang Yufen 	}
1653db20fd2bSAlexei Starovoitov 
16543af43ba4SHou Tao 	err = bpf_map_update_value(map, f.file, key, value, attr->flags);
165567ad2c73SHou Tao 	if (!err)
165637ba5b59SHou Tao 		maybe_wait_bpf_programs(map);
16576710e112SJesper Dangaard Brouer 
1658f0dce1d9SStanislav Fomichev 	kvfree(value);
1659db20fd2bSAlexei Starovoitov free_key:
166044779a4bSStanislav Fomichev 	kvfree(key);
1661db20fd2bSAlexei Starovoitov err_put:
1662353050beSDaniel Borkmann 	bpf_map_write_active_dec(map);
1663db20fd2bSAlexei Starovoitov 	fdput(f);
1664db20fd2bSAlexei Starovoitov 	return err;
1665db20fd2bSAlexei Starovoitov }
1666db20fd2bSAlexei Starovoitov 
1667db20fd2bSAlexei Starovoitov #define BPF_MAP_DELETE_ELEM_LAST_FIELD key
1668db20fd2bSAlexei Starovoitov 
map_delete_elem(union bpf_attr * attr,bpfptr_t uattr)1669b88df697SBenjamin Tissoires static int map_delete_elem(union bpf_attr *attr, bpfptr_t uattr)
1670db20fd2bSAlexei Starovoitov {
1671b88df697SBenjamin Tissoires 	bpfptr_t ukey = make_bpfptr(attr->key, uattr.is_kernel);
1672db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1673db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1674592867bfSDaniel Borkmann 	struct fd f;
1675db20fd2bSAlexei Starovoitov 	void *key;
1676db20fd2bSAlexei Starovoitov 	int err;
1677db20fd2bSAlexei Starovoitov 
1678db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_DELETE_ELEM))
1679db20fd2bSAlexei Starovoitov 		return -EINVAL;
1680db20fd2bSAlexei Starovoitov 
1681592867bfSDaniel Borkmann 	f = fdget(ufd);
1682c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1683db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1684db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
1685353050beSDaniel Borkmann 	bpf_map_write_active_inc(map);
168687df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
16876e71b04aSChenbo Feng 		err = -EPERM;
16886e71b04aSChenbo Feng 		goto err_put;
16896e71b04aSChenbo Feng 	}
16906e71b04aSChenbo Feng 
1691b88df697SBenjamin Tissoires 	key = ___bpf_copy_key(ukey, map->key_size);
1692e4448ed8SAl Viro 	if (IS_ERR(key)) {
1693e4448ed8SAl Viro 		err = PTR_ERR(key);
1694db20fd2bSAlexei Starovoitov 		goto err_put;
1695e4448ed8SAl Viro 	}
1696db20fd2bSAlexei Starovoitov 
16979d03ebc7SStanislav Fomichev 	if (bpf_map_is_offloaded(map)) {
1698a3884572SJakub Kicinski 		err = bpf_map_offload_delete_elem(map, key);
1699a3884572SJakub Kicinski 		goto out;
170085d33df3SMartin KaFai Lau 	} else if (IS_FD_PROG_ARRAY(map) ||
170185d33df3SMartin KaFai Lau 		   map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
170285d33df3SMartin KaFai Lau 		/* These maps require sleepable context */
1703da765a2fSDaniel Borkmann 		err = map->ops->map_delete_elem(map, key);
1704da765a2fSDaniel Borkmann 		goto out;
1705a3884572SJakub Kicinski 	}
1706a3884572SJakub Kicinski 
1707b6e5dae1SThomas Gleixner 	bpf_disable_instrumentation();
1708db20fd2bSAlexei Starovoitov 	rcu_read_lock();
1709db20fd2bSAlexei Starovoitov 	err = map->ops->map_delete_elem(map, key);
1710db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
1711b6e5dae1SThomas Gleixner 	bpf_enable_instrumentation();
171267ad2c73SHou Tao 	if (!err)
17131ae80cf3SDaniel Colascione 		maybe_wait_bpf_programs(map);
1714a3884572SJakub Kicinski out:
171544779a4bSStanislav Fomichev 	kvfree(key);
1716db20fd2bSAlexei Starovoitov err_put:
1717353050beSDaniel Borkmann 	bpf_map_write_active_dec(map);
1718db20fd2bSAlexei Starovoitov 	fdput(f);
1719db20fd2bSAlexei Starovoitov 	return err;
1720db20fd2bSAlexei Starovoitov }
1721db20fd2bSAlexei Starovoitov 
1722db20fd2bSAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
1723db20fd2bSAlexei Starovoitov #define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key
1724db20fd2bSAlexei Starovoitov 
map_get_next_key(union bpf_attr * attr)1725db20fd2bSAlexei Starovoitov static int map_get_next_key(union bpf_attr *attr)
1726db20fd2bSAlexei Starovoitov {
1727535e7b4bSMickaël Salaün 	void __user *ukey = u64_to_user_ptr(attr->key);
1728535e7b4bSMickaël Salaün 	void __user *unext_key = u64_to_user_ptr(attr->next_key);
1729db20fd2bSAlexei Starovoitov 	int ufd = attr->map_fd;
1730db20fd2bSAlexei Starovoitov 	struct bpf_map *map;
1731db20fd2bSAlexei Starovoitov 	void *key, *next_key;
1732592867bfSDaniel Borkmann 	struct fd f;
1733db20fd2bSAlexei Starovoitov 	int err;
1734db20fd2bSAlexei Starovoitov 
1735db20fd2bSAlexei Starovoitov 	if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY))
1736db20fd2bSAlexei Starovoitov 		return -EINVAL;
1737db20fd2bSAlexei Starovoitov 
1738592867bfSDaniel Borkmann 	f = fdget(ufd);
1739c2101297SDaniel Borkmann 	map = __bpf_map_get(f);
1740db20fd2bSAlexei Starovoitov 	if (IS_ERR(map))
1741db20fd2bSAlexei Starovoitov 		return PTR_ERR(map);
174287df15deSDaniel Borkmann 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
17436e71b04aSChenbo Feng 		err = -EPERM;
17446e71b04aSChenbo Feng 		goto err_put;
17456e71b04aSChenbo Feng 	}
17466e71b04aSChenbo Feng 
17478fe45924STeng Qin 	if (ukey) {
1748c9d29f46SMauricio Vasquez B 		key = __bpf_copy_key(ukey, map->key_size);
1749e4448ed8SAl Viro 		if (IS_ERR(key)) {
1750e4448ed8SAl Viro 			err = PTR_ERR(key);
1751db20fd2bSAlexei Starovoitov 			goto err_put;
1752e4448ed8SAl Viro 		}
17538fe45924STeng Qin 	} else {
17548fe45924STeng Qin 		key = NULL;
17558fe45924STeng Qin 	}
1756db20fd2bSAlexei Starovoitov 
1757db20fd2bSAlexei Starovoitov 	err = -ENOMEM;
175844779a4bSStanislav Fomichev 	next_key = kvmalloc(map->key_size, GFP_USER);
1759db20fd2bSAlexei Starovoitov 	if (!next_key)
1760db20fd2bSAlexei Starovoitov 		goto free_key;
1761db20fd2bSAlexei Starovoitov 
17629d03ebc7SStanislav Fomichev 	if (bpf_map_is_offloaded(map)) {
1763a3884572SJakub Kicinski 		err = bpf_map_offload_get_next_key(map, key, next_key);
1764a3884572SJakub Kicinski 		goto out;
1765a3884572SJakub Kicinski 	}
1766a3884572SJakub Kicinski 
1767db20fd2bSAlexei Starovoitov 	rcu_read_lock();
1768db20fd2bSAlexei Starovoitov 	err = map->ops->map_get_next_key(map, key, next_key);
1769db20fd2bSAlexei Starovoitov 	rcu_read_unlock();
1770a3884572SJakub Kicinski out:
1771db20fd2bSAlexei Starovoitov 	if (err)
1772db20fd2bSAlexei Starovoitov 		goto free_next_key;
1773db20fd2bSAlexei Starovoitov 
1774db20fd2bSAlexei Starovoitov 	err = -EFAULT;
1775db20fd2bSAlexei Starovoitov 	if (copy_to_user(unext_key, next_key, map->key_size) != 0)
1776db20fd2bSAlexei Starovoitov 		goto free_next_key;
1777db20fd2bSAlexei Starovoitov 
1778db20fd2bSAlexei Starovoitov 	err = 0;
1779db20fd2bSAlexei Starovoitov 
1780db20fd2bSAlexei Starovoitov free_next_key:
178144779a4bSStanislav Fomichev 	kvfree(next_key);
1782db20fd2bSAlexei Starovoitov free_key:
178344779a4bSStanislav Fomichev 	kvfree(key);
1784db20fd2bSAlexei Starovoitov err_put:
1785db20fd2bSAlexei Starovoitov 	fdput(f);
1786db20fd2bSAlexei Starovoitov 	return err;
1787db20fd2bSAlexei Starovoitov }
1788db20fd2bSAlexei Starovoitov 
generic_map_delete_batch(struct bpf_map * map,const union bpf_attr * attr,union bpf_attr __user * uattr)1789aa2e93b8SBrian Vazquez int generic_map_delete_batch(struct bpf_map *map,
1790aa2e93b8SBrian Vazquez 			     const union bpf_attr *attr,
1791aa2e93b8SBrian Vazquez 			     union bpf_attr __user *uattr)
1792aa2e93b8SBrian Vazquez {
1793aa2e93b8SBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1794aa2e93b8SBrian Vazquez 	u32 cp, max_count;
1795aa2e93b8SBrian Vazquez 	int err = 0;
1796aa2e93b8SBrian Vazquez 	void *key;
1797aa2e93b8SBrian Vazquez 
1798aa2e93b8SBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1799aa2e93b8SBrian Vazquez 		return -EINVAL;
1800aa2e93b8SBrian Vazquez 
1801aa2e93b8SBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1802db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
1803aa2e93b8SBrian Vazquez 		return -EINVAL;
1804aa2e93b8SBrian Vazquez 	}
1805aa2e93b8SBrian Vazquez 
1806aa2e93b8SBrian Vazquez 	max_count = attr->batch.count;
1807aa2e93b8SBrian Vazquez 	if (!max_count)
1808aa2e93b8SBrian Vazquez 		return 0;
1809aa2e93b8SBrian Vazquez 
181006e5c999SHou Tao 	if (put_user(0, &uattr->batch.count))
181106e5c999SHou Tao 		return -EFAULT;
181206e5c999SHou Tao 
181344779a4bSStanislav Fomichev 	key = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
18142e3a94aaSBrian Vazquez 	if (!key)
18152e3a94aaSBrian Vazquez 		return -ENOMEM;
18162e3a94aaSBrian Vazquez 
1817aa2e93b8SBrian Vazquez 	for (cp = 0; cp < max_count; cp++) {
18182e3a94aaSBrian Vazquez 		err = -EFAULT;
18192e3a94aaSBrian Vazquez 		if (copy_from_user(key, keys + cp * map->key_size,
18202e3a94aaSBrian Vazquez 				   map->key_size))
1821aa2e93b8SBrian Vazquez 			break;
1822aa2e93b8SBrian Vazquez 
18239d03ebc7SStanislav Fomichev 		if (bpf_map_is_offloaded(map)) {
1824aa2e93b8SBrian Vazquez 			err = bpf_map_offload_delete_elem(map, key);
1825aa2e93b8SBrian Vazquez 			break;
1826aa2e93b8SBrian Vazquez 		}
1827aa2e93b8SBrian Vazquez 
1828b6e5dae1SThomas Gleixner 		bpf_disable_instrumentation();
1829aa2e93b8SBrian Vazquez 		rcu_read_lock();
1830aa2e93b8SBrian Vazquez 		err = map->ops->map_delete_elem(map, key);
1831aa2e93b8SBrian Vazquez 		rcu_read_unlock();
1832b6e5dae1SThomas Gleixner 		bpf_enable_instrumentation();
1833aa2e93b8SBrian Vazquez 		if (err)
1834aa2e93b8SBrian Vazquez 			break;
183575134f16SEric Dumazet 		cond_resched();
1836aa2e93b8SBrian Vazquez 	}
1837aa2e93b8SBrian Vazquez 	if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp)))
1838aa2e93b8SBrian Vazquez 		err = -EFAULT;
18392e3a94aaSBrian Vazquez 
184044779a4bSStanislav Fomichev 	kvfree(key);
18419087c6ffSEric Dumazet 
1842aa2e93b8SBrian Vazquez 	return err;
1843aa2e93b8SBrian Vazquez }
1844aa2e93b8SBrian Vazquez 
generic_map_update_batch(struct bpf_map * map,struct file * map_file,const union bpf_attr * attr,union bpf_attr __user * uattr)18453af43ba4SHou Tao int generic_map_update_batch(struct bpf_map *map, struct file *map_file,
1846aa2e93b8SBrian Vazquez 			     const union bpf_attr *attr,
1847aa2e93b8SBrian Vazquez 			     union bpf_attr __user *uattr)
1848aa2e93b8SBrian Vazquez {
1849aa2e93b8SBrian Vazquez 	void __user *values = u64_to_user_ptr(attr->batch.values);
1850aa2e93b8SBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1851aa2e93b8SBrian Vazquez 	u32 value_size, cp, max_count;
1852aa2e93b8SBrian Vazquez 	void *key, *value;
1853aa2e93b8SBrian Vazquez 	int err = 0;
1854aa2e93b8SBrian Vazquez 
1855aa2e93b8SBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1856aa2e93b8SBrian Vazquez 		return -EINVAL;
1857aa2e93b8SBrian Vazquez 
1858aa2e93b8SBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1859db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
1860aa2e93b8SBrian Vazquez 		return -EINVAL;
1861aa2e93b8SBrian Vazquez 	}
1862aa2e93b8SBrian Vazquez 
1863aa2e93b8SBrian Vazquez 	value_size = bpf_map_value_size(map);
1864aa2e93b8SBrian Vazquez 
1865aa2e93b8SBrian Vazquez 	max_count = attr->batch.count;
1866aa2e93b8SBrian Vazquez 	if (!max_count)
1867aa2e93b8SBrian Vazquez 		return 0;
1868aa2e93b8SBrian Vazquez 
186906e5c999SHou Tao 	if (put_user(0, &uattr->batch.count))
187006e5c999SHou Tao 		return -EFAULT;
187106e5c999SHou Tao 
187244779a4bSStanislav Fomichev 	key = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
18732e3a94aaSBrian Vazquez 	if (!key)
1874aa2e93b8SBrian Vazquez 		return -ENOMEM;
1875aa2e93b8SBrian Vazquez 
1876f0dce1d9SStanislav Fomichev 	value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN);
18772e3a94aaSBrian Vazquez 	if (!value) {
187844779a4bSStanislav Fomichev 		kvfree(key);
18792e3a94aaSBrian Vazquez 		return -ENOMEM;
1880aa2e93b8SBrian Vazquez 	}
18812e3a94aaSBrian Vazquez 
18822e3a94aaSBrian Vazquez 	for (cp = 0; cp < max_count; cp++) {
1883aa2e93b8SBrian Vazquez 		err = -EFAULT;
18842e3a94aaSBrian Vazquez 		if (copy_from_user(key, keys + cp * map->key_size,
18852e3a94aaSBrian Vazquez 		    map->key_size) ||
18862e3a94aaSBrian Vazquez 		    copy_from_user(value, values + cp * value_size, value_size))
1887aa2e93b8SBrian Vazquez 			break;
1888aa2e93b8SBrian Vazquez 
18893af43ba4SHou Tao 		err = bpf_map_update_value(map, map_file, key, value,
1890aa2e93b8SBrian Vazquez 					   attr->batch.elem_flags);
1891aa2e93b8SBrian Vazquez 
1892aa2e93b8SBrian Vazquez 		if (err)
1893aa2e93b8SBrian Vazquez 			break;
189475134f16SEric Dumazet 		cond_resched();
1895aa2e93b8SBrian Vazquez 	}
1896aa2e93b8SBrian Vazquez 
1897aa2e93b8SBrian Vazquez 	if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp)))
1898aa2e93b8SBrian Vazquez 		err = -EFAULT;
1899aa2e93b8SBrian Vazquez 
1900f0dce1d9SStanislav Fomichev 	kvfree(value);
190144779a4bSStanislav Fomichev 	kvfree(key);
190237ba5b59SHou Tao 
1903aa2e93b8SBrian Vazquez 	return err;
1904aa2e93b8SBrian Vazquez }
1905aa2e93b8SBrian Vazquez 
1906cb4d03abSBrian Vazquez #define MAP_LOOKUP_RETRIES 3
1907cb4d03abSBrian Vazquez 
generic_map_lookup_batch(struct bpf_map * map,const union bpf_attr * attr,union bpf_attr __user * uattr)1908cb4d03abSBrian Vazquez int generic_map_lookup_batch(struct bpf_map *map,
1909cb4d03abSBrian Vazquez 				    const union bpf_attr *attr,
1910cb4d03abSBrian Vazquez 				    union bpf_attr __user *uattr)
1911cb4d03abSBrian Vazquez {
1912cb4d03abSBrian Vazquez 	void __user *uobatch = u64_to_user_ptr(attr->batch.out_batch);
1913cb4d03abSBrian Vazquez 	void __user *ubatch = u64_to_user_ptr(attr->batch.in_batch);
1914cb4d03abSBrian Vazquez 	void __user *values = u64_to_user_ptr(attr->batch.values);
1915cb4d03abSBrian Vazquez 	void __user *keys = u64_to_user_ptr(attr->batch.keys);
1916cb4d03abSBrian Vazquez 	void *buf, *buf_prevkey, *prev_key, *key, *value;
1917cb4d03abSBrian Vazquez 	int err, retry = MAP_LOOKUP_RETRIES;
1918cb4d03abSBrian Vazquez 	u32 value_size, cp, max_count;
1919cb4d03abSBrian Vazquez 
1920cb4d03abSBrian Vazquez 	if (attr->batch.elem_flags & ~BPF_F_LOCK)
1921cb4d03abSBrian Vazquez 		return -EINVAL;
1922cb4d03abSBrian Vazquez 
1923cb4d03abSBrian Vazquez 	if ((attr->batch.elem_flags & BPF_F_LOCK) &&
1924db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK))
1925cb4d03abSBrian Vazquez 		return -EINVAL;
1926cb4d03abSBrian Vazquez 
1927cb4d03abSBrian Vazquez 	value_size = bpf_map_value_size(map);
1928cb4d03abSBrian Vazquez 
1929cb4d03abSBrian Vazquez 	max_count = attr->batch.count;
1930cb4d03abSBrian Vazquez 	if (!max_count)
1931cb4d03abSBrian Vazquez 		return 0;
1932cb4d03abSBrian Vazquez 
1933cb4d03abSBrian Vazquez 	if (put_user(0, &uattr->batch.count))
1934cb4d03abSBrian Vazquez 		return -EFAULT;
1935cb4d03abSBrian Vazquez 
193644779a4bSStanislav Fomichev 	buf_prevkey = kvmalloc(map->key_size, GFP_USER | __GFP_NOWARN);
1937cb4d03abSBrian Vazquez 	if (!buf_prevkey)
1938cb4d03abSBrian Vazquez 		return -ENOMEM;
1939cb4d03abSBrian Vazquez 
1940f0dce1d9SStanislav Fomichev 	buf = kvmalloc(map->key_size + value_size, GFP_USER | __GFP_NOWARN);
1941cb4d03abSBrian Vazquez 	if (!buf) {
194244779a4bSStanislav Fomichev 		kvfree(buf_prevkey);
1943cb4d03abSBrian Vazquez 		return -ENOMEM;
1944cb4d03abSBrian Vazquez 	}
1945cb4d03abSBrian Vazquez 
1946cb4d03abSBrian Vazquez 	err = -EFAULT;
1947cb4d03abSBrian Vazquez 	prev_key = NULL;
1948cb4d03abSBrian Vazquez 	if (ubatch && copy_from_user(buf_prevkey, ubatch, map->key_size))
1949cb4d03abSBrian Vazquez 		goto free_buf;
1950cb4d03abSBrian Vazquez 	key = buf;
1951cb4d03abSBrian Vazquez 	value = key + map->key_size;
1952cb4d03abSBrian Vazquez 	if (ubatch)
1953cb4d03abSBrian Vazquez 		prev_key = buf_prevkey;
1954cb4d03abSBrian Vazquez 
1955cb4d03abSBrian Vazquez 	for (cp = 0; cp < max_count;) {
1956cb4d03abSBrian Vazquez 		rcu_read_lock();
1957cb4d03abSBrian Vazquez 		err = map->ops->map_get_next_key(map, prev_key, key);
1958cb4d03abSBrian Vazquez 		rcu_read_unlock();
1959cb4d03abSBrian Vazquez 		if (err)
1960cb4d03abSBrian Vazquez 			break;
1961cb4d03abSBrian Vazquez 		err = bpf_map_copy_value(map, key, value,
1962cb4d03abSBrian Vazquez 					 attr->batch.elem_flags);
1963cb4d03abSBrian Vazquez 
1964cb4d03abSBrian Vazquez 		if (err == -ENOENT) {
1965cb4d03abSBrian Vazquez 			if (retry) {
1966cb4d03abSBrian Vazquez 				retry--;
1967cb4d03abSBrian Vazquez 				continue;
1968cb4d03abSBrian Vazquez 			}
1969cb4d03abSBrian Vazquez 			err = -EINTR;
1970cb4d03abSBrian Vazquez 			break;
1971cb4d03abSBrian Vazquez 		}
1972cb4d03abSBrian Vazquez 
1973cb4d03abSBrian Vazquez 		if (err)
1974cb4d03abSBrian Vazquez 			goto free_buf;
1975cb4d03abSBrian Vazquez 
1976cb4d03abSBrian Vazquez 		if (copy_to_user(keys + cp * map->key_size, key,
1977cb4d03abSBrian Vazquez 				 map->key_size)) {
1978cb4d03abSBrian Vazquez 			err = -EFAULT;
1979cb4d03abSBrian Vazquez 			goto free_buf;
1980cb4d03abSBrian Vazquez 		}
1981cb4d03abSBrian Vazquez 		if (copy_to_user(values + cp * value_size, value, value_size)) {
1982cb4d03abSBrian Vazquez 			err = -EFAULT;
1983cb4d03abSBrian Vazquez 			goto free_buf;
1984cb4d03abSBrian Vazquez 		}
1985cb4d03abSBrian Vazquez 
1986cb4d03abSBrian Vazquez 		if (!prev_key)
1987cb4d03abSBrian Vazquez 			prev_key = buf_prevkey;
1988cb4d03abSBrian Vazquez 
1989cb4d03abSBrian Vazquez 		swap(prev_key, key);
1990cb4d03abSBrian Vazquez 		retry = MAP_LOOKUP_RETRIES;
1991cb4d03abSBrian Vazquez 		cp++;
199275134f16SEric Dumazet 		cond_resched();
1993cb4d03abSBrian Vazquez 	}
1994cb4d03abSBrian Vazquez 
1995cb4d03abSBrian Vazquez 	if (err == -EFAULT)
1996cb4d03abSBrian Vazquez 		goto free_buf;
1997cb4d03abSBrian Vazquez 
1998cb4d03abSBrian Vazquez 	if ((copy_to_user(&uattr->batch.count, &cp, sizeof(cp)) ||
1999cb4d03abSBrian Vazquez 		    (cp && copy_to_user(uobatch, prev_key, map->key_size))))
2000cb4d03abSBrian Vazquez 		err = -EFAULT;
2001cb4d03abSBrian Vazquez 
2002cb4d03abSBrian Vazquez free_buf:
200344779a4bSStanislav Fomichev 	kvfree(buf_prevkey);
2004f0dce1d9SStanislav Fomichev 	kvfree(buf);
2005cb4d03abSBrian Vazquez 	return err;
2006cb4d03abSBrian Vazquez }
2007cb4d03abSBrian Vazquez 
20083e87f192SDenis Salopek #define BPF_MAP_LOOKUP_AND_DELETE_ELEM_LAST_FIELD flags
2009bd513cd0SMauricio Vasquez B 
map_lookup_and_delete_elem(union bpf_attr * attr)2010bd513cd0SMauricio Vasquez B static int map_lookup_and_delete_elem(union bpf_attr *attr)
2011bd513cd0SMauricio Vasquez B {
2012bd513cd0SMauricio Vasquez B 	void __user *ukey = u64_to_user_ptr(attr->key);
2013bd513cd0SMauricio Vasquez B 	void __user *uvalue = u64_to_user_ptr(attr->value);
2014bd513cd0SMauricio Vasquez B 	int ufd = attr->map_fd;
2015bd513cd0SMauricio Vasquez B 	struct bpf_map *map;
2016540fefc0SAlexei Starovoitov 	void *key, *value;
2017bd513cd0SMauricio Vasquez B 	u32 value_size;
2018bd513cd0SMauricio Vasquez B 	struct fd f;
2019bd513cd0SMauricio Vasquez B 	int err;
2020bd513cd0SMauricio Vasquez B 
2021bd513cd0SMauricio Vasquez B 	if (CHECK_ATTR(BPF_MAP_LOOKUP_AND_DELETE_ELEM))
2022bd513cd0SMauricio Vasquez B 		return -EINVAL;
2023bd513cd0SMauricio Vasquez B 
20243e87f192SDenis Salopek 	if (attr->flags & ~BPF_F_LOCK)
20253e87f192SDenis Salopek 		return -EINVAL;
20263e87f192SDenis Salopek 
2027bd513cd0SMauricio Vasquez B 	f = fdget(ufd);
2028bd513cd0SMauricio Vasquez B 	map = __bpf_map_get(f);
2029bd513cd0SMauricio Vasquez B 	if (IS_ERR(map))
2030bd513cd0SMauricio Vasquez B 		return PTR_ERR(map);
2031353050beSDaniel Borkmann 	bpf_map_write_active_inc(map);
20321ea0f912SAnton Protopopov 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_READ) ||
20331ea0f912SAnton Protopopov 	    !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
2034bd513cd0SMauricio Vasquez B 		err = -EPERM;
2035bd513cd0SMauricio Vasquez B 		goto err_put;
2036bd513cd0SMauricio Vasquez B 	}
2037bd513cd0SMauricio Vasquez B 
20383e87f192SDenis Salopek 	if (attr->flags &&
20393e87f192SDenis Salopek 	    (map->map_type == BPF_MAP_TYPE_QUEUE ||
20403e87f192SDenis Salopek 	     map->map_type == BPF_MAP_TYPE_STACK)) {
20413e87f192SDenis Salopek 		err = -EINVAL;
20423e87f192SDenis Salopek 		goto err_put;
20433e87f192SDenis Salopek 	}
20443e87f192SDenis Salopek 
20453e87f192SDenis Salopek 	if ((attr->flags & BPF_F_LOCK) &&
2046db559117SKumar Kartikeya Dwivedi 	    !btf_record_has_field(map->record, BPF_SPIN_LOCK)) {
20473e87f192SDenis Salopek 		err = -EINVAL;
20483e87f192SDenis Salopek 		goto err_put;
20493e87f192SDenis Salopek 	}
20503e87f192SDenis Salopek 
2051bd513cd0SMauricio Vasquez B 	key = __bpf_copy_key(ukey, map->key_size);
2052bd513cd0SMauricio Vasquez B 	if (IS_ERR(key)) {
2053bd513cd0SMauricio Vasquez B 		err = PTR_ERR(key);
2054bd513cd0SMauricio Vasquez B 		goto err_put;
2055bd513cd0SMauricio Vasquez B 	}
2056bd513cd0SMauricio Vasquez B 
20573e87f192SDenis Salopek 	value_size = bpf_map_value_size(map);
2058bd513cd0SMauricio Vasquez B 
2059bd513cd0SMauricio Vasquez B 	err = -ENOMEM;
2060f0dce1d9SStanislav Fomichev 	value = kvmalloc(value_size, GFP_USER | __GFP_NOWARN);
2061bd513cd0SMauricio Vasquez B 	if (!value)
2062bd513cd0SMauricio Vasquez B 		goto free_key;
2063bd513cd0SMauricio Vasquez B 
20643e87f192SDenis Salopek 	err = -ENOTSUPP;
2065bd513cd0SMauricio Vasquez B 	if (map->map_type == BPF_MAP_TYPE_QUEUE ||
2066bd513cd0SMauricio Vasquez B 	    map->map_type == BPF_MAP_TYPE_STACK) {
2067bd513cd0SMauricio Vasquez B 		err = map->ops->map_pop_elem(map, value);
20683e87f192SDenis Salopek 	} else if (map->map_type == BPF_MAP_TYPE_HASH ||
20693e87f192SDenis Salopek 		   map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
20703e87f192SDenis Salopek 		   map->map_type == BPF_MAP_TYPE_LRU_HASH ||
20713e87f192SDenis Salopek 		   map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
20729d03ebc7SStanislav Fomichev 		if (!bpf_map_is_offloaded(map)) {
20733e87f192SDenis Salopek 			bpf_disable_instrumentation();
20743e87f192SDenis Salopek 			rcu_read_lock();
20753e87f192SDenis Salopek 			err = map->ops->map_lookup_and_delete_elem(map, key, value, attr->flags);
20763e87f192SDenis Salopek 			rcu_read_unlock();
20773e87f192SDenis Salopek 			bpf_enable_instrumentation();
20783e87f192SDenis Salopek 		}
2079bd513cd0SMauricio Vasquez B 	}
2080bd513cd0SMauricio Vasquez B 
2081bd513cd0SMauricio Vasquez B 	if (err)
2082bd513cd0SMauricio Vasquez B 		goto free_value;
2083bd513cd0SMauricio Vasquez B 
20847f645462SWei Yongjun 	if (copy_to_user(uvalue, value, value_size) != 0) {
20857f645462SWei Yongjun 		err = -EFAULT;
2086bd513cd0SMauricio Vasquez B 		goto free_value;
20877f645462SWei Yongjun 	}
2088bd513cd0SMauricio Vasquez B 
2089bd513cd0SMauricio Vasquez B 	err = 0;
2090bd513cd0SMauricio Vasquez B 
2091bd513cd0SMauricio Vasquez B free_value:
2092f0dce1d9SStanislav Fomichev 	kvfree(value);
2093bd513cd0SMauricio Vasquez B free_key:
209444779a4bSStanislav Fomichev 	kvfree(key);
2095bd513cd0SMauricio Vasquez B err_put:
2096353050beSDaniel Borkmann 	bpf_map_write_active_dec(map);
2097bd513cd0SMauricio Vasquez B 	fdput(f);
2098bd513cd0SMauricio Vasquez B 	return err;
2099bd513cd0SMauricio Vasquez B }
2100bd513cd0SMauricio Vasquez B 
210187df15deSDaniel Borkmann #define BPF_MAP_FREEZE_LAST_FIELD map_fd
210287df15deSDaniel Borkmann 
map_freeze(const union bpf_attr * attr)210387df15deSDaniel Borkmann static int map_freeze(const union bpf_attr *attr)
210487df15deSDaniel Borkmann {
210587df15deSDaniel Borkmann 	int err = 0, ufd = attr->map_fd;
210687df15deSDaniel Borkmann 	struct bpf_map *map;
210787df15deSDaniel Borkmann 	struct fd f;
210887df15deSDaniel Borkmann 
210987df15deSDaniel Borkmann 	if (CHECK_ATTR(BPF_MAP_FREEZE))
211087df15deSDaniel Borkmann 		return -EINVAL;
211187df15deSDaniel Borkmann 
211287df15deSDaniel Borkmann 	f = fdget(ufd);
211387df15deSDaniel Borkmann 	map = __bpf_map_get(f);
211487df15deSDaniel Borkmann 	if (IS_ERR(map))
211587df15deSDaniel Borkmann 		return PTR_ERR(map);
2116fc970227SAndrii Nakryiko 
2117db559117SKumar Kartikeya Dwivedi 	if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS || !IS_ERR_OR_NULL(map->record)) {
2118849b4d94SMartin KaFai Lau 		fdput(f);
2119849b4d94SMartin KaFai Lau 		return -ENOTSUPP;
2120849b4d94SMartin KaFai Lau 	}
2121849b4d94SMartin KaFai Lau 
2122c4c84f6fSAndrii Nakryiko 	if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
21234266f41fSDaniel Borkmann 		fdput(f);
21244266f41fSDaniel Borkmann 		return -EPERM;
2125c4c84f6fSAndrii Nakryiko 	}
2126c4c84f6fSAndrii Nakryiko 
2127fc970227SAndrii Nakryiko 	mutex_lock(&map->freeze_mutex);
2128353050beSDaniel Borkmann 	if (bpf_map_write_active(map)) {
2129fc970227SAndrii Nakryiko 		err = -EBUSY;
2130fc970227SAndrii Nakryiko 		goto err_put;
2131fc970227SAndrii Nakryiko 	}
213287df15deSDaniel Borkmann 	if (READ_ONCE(map->frozen)) {
213387df15deSDaniel Borkmann 		err = -EBUSY;
213487df15deSDaniel Borkmann 		goto err_put;
213587df15deSDaniel Borkmann 	}
213687df15deSDaniel Borkmann 
213787df15deSDaniel Borkmann 	WRITE_ONCE(map->frozen, true);
213887df15deSDaniel Borkmann err_put:
2139fc970227SAndrii Nakryiko 	mutex_unlock(&map->freeze_mutex);
214087df15deSDaniel Borkmann 	fdput(f);
214187df15deSDaniel Borkmann 	return err;
214287df15deSDaniel Borkmann }
214387df15deSDaniel Borkmann 
21447de16e3aSJakub Kicinski static const struct bpf_prog_ops * const bpf_prog_types[] = {
214591cc1a99SAlexei Starovoitov #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) \
21467de16e3aSJakub Kicinski 	[_id] = & _name ## _prog_ops,
21477de16e3aSJakub Kicinski #define BPF_MAP_TYPE(_id, _ops)
2148f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name)
21497de16e3aSJakub Kicinski #include <linux/bpf_types.h>
21507de16e3aSJakub Kicinski #undef BPF_PROG_TYPE
21517de16e3aSJakub Kicinski #undef BPF_MAP_TYPE
2152f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE
21537de16e3aSJakub Kicinski };
21547de16e3aSJakub Kicinski 
find_prog_type(enum bpf_prog_type type,struct bpf_prog * prog)215509756af4SAlexei Starovoitov static int find_prog_type(enum bpf_prog_type type, struct bpf_prog *prog)
215609756af4SAlexei Starovoitov {
2157d0f1a451SDaniel Borkmann 	const struct bpf_prog_ops *ops;
2158d0f1a451SDaniel Borkmann 
2159d0f1a451SDaniel Borkmann 	if (type >= ARRAY_SIZE(bpf_prog_types))
2160d0f1a451SDaniel Borkmann 		return -EINVAL;
2161d0f1a451SDaniel Borkmann 	type = array_index_nospec(type, ARRAY_SIZE(bpf_prog_types));
2162d0f1a451SDaniel Borkmann 	ops = bpf_prog_types[type];
2163d0f1a451SDaniel Borkmann 	if (!ops)
2164be9370a7SJohannes Berg 		return -EINVAL;
216509756af4SAlexei Starovoitov 
21669d03ebc7SStanislav Fomichev 	if (!bpf_prog_is_offloaded(prog->aux))
2167d0f1a451SDaniel Borkmann 		prog->aux->ops = ops;
2168ab3f0063SJakub Kicinski 	else
2169ab3f0063SJakub Kicinski 		prog->aux->ops = &bpf_offload_prog_ops;
217024701eceSDaniel Borkmann 	prog->type = type;
217109756af4SAlexei Starovoitov 	return 0;
217209756af4SAlexei Starovoitov }
217309756af4SAlexei Starovoitov 
2174bae141f5SDaniel Borkmann enum bpf_audit {
2175bae141f5SDaniel Borkmann 	BPF_AUDIT_LOAD,
2176bae141f5SDaniel Borkmann 	BPF_AUDIT_UNLOAD,
2177bae141f5SDaniel Borkmann 	BPF_AUDIT_MAX,
2178bae141f5SDaniel Borkmann };
2179bae141f5SDaniel Borkmann 
2180bae141f5SDaniel Borkmann static const char * const bpf_audit_str[BPF_AUDIT_MAX] = {
2181bae141f5SDaniel Borkmann 	[BPF_AUDIT_LOAD]   = "LOAD",
2182bae141f5SDaniel Borkmann 	[BPF_AUDIT_UNLOAD] = "UNLOAD",
2183bae141f5SDaniel Borkmann };
2184bae141f5SDaniel Borkmann 
bpf_audit_prog(const struct bpf_prog * prog,unsigned int op)2185bae141f5SDaniel Borkmann static void bpf_audit_prog(const struct bpf_prog *prog, unsigned int op)
2186bae141f5SDaniel Borkmann {
2187bae141f5SDaniel Borkmann 	struct audit_context *ctx = NULL;
2188bae141f5SDaniel Borkmann 	struct audit_buffer *ab;
2189bae141f5SDaniel Borkmann 
2190bae141f5SDaniel Borkmann 	if (WARN_ON_ONCE(op >= BPF_AUDIT_MAX))
2191bae141f5SDaniel Borkmann 		return;
2192bae141f5SDaniel Borkmann 	if (audit_enabled == AUDIT_OFF)
2193bae141f5SDaniel Borkmann 		return;
2194ef01f4e2SPaul Moore 	if (!in_irq() && !irqs_disabled())
2195bae141f5SDaniel Borkmann 		ctx = audit_context();
2196bae141f5SDaniel Borkmann 	ab = audit_log_start(ctx, GFP_ATOMIC, AUDIT_BPF);
2197bae141f5SDaniel Borkmann 	if (unlikely(!ab))
2198bae141f5SDaniel Borkmann 		return;
2199bae141f5SDaniel Borkmann 	audit_log_format(ab, "prog-id=%u op=%s",
2200bae141f5SDaniel Borkmann 			 prog->aux->id, bpf_audit_str[op]);
2201bae141f5SDaniel Borkmann 	audit_log_end(ab);
2202bae141f5SDaniel Borkmann }
2203bae141f5SDaniel Borkmann 
bpf_prog_alloc_id(struct bpf_prog * prog)2204dc4bb0e2SMartin KaFai Lau static int bpf_prog_alloc_id(struct bpf_prog *prog)
2205dc4bb0e2SMartin KaFai Lau {
2206dc4bb0e2SMartin KaFai Lau 	int id;
2207dc4bb0e2SMartin KaFai Lau 
2208b76354cdSShaohua Li 	idr_preload(GFP_KERNEL);
2209dc4bb0e2SMartin KaFai Lau 	spin_lock_bh(&prog_idr_lock);
2210dc4bb0e2SMartin KaFai Lau 	id = idr_alloc_cyclic(&prog_idr, prog, 1, INT_MAX, GFP_ATOMIC);
2211dc4bb0e2SMartin KaFai Lau 	if (id > 0)
2212dc4bb0e2SMartin KaFai Lau 		prog->aux->id = id;
2213dc4bb0e2SMartin KaFai Lau 	spin_unlock_bh(&prog_idr_lock);
2214b76354cdSShaohua Li 	idr_preload_end();
2215dc4bb0e2SMartin KaFai Lau 
2216dc4bb0e2SMartin KaFai Lau 	/* id is in [1, INT_MAX) */
2217dc4bb0e2SMartin KaFai Lau 	if (WARN_ON_ONCE(!id))
2218dc4bb0e2SMartin KaFai Lau 		return -ENOSPC;
2219dc4bb0e2SMartin KaFai Lau 
2220dc4bb0e2SMartin KaFai Lau 	return id > 0 ? 0 : id;
2221dc4bb0e2SMartin KaFai Lau }
2222dc4bb0e2SMartin KaFai Lau 
bpf_prog_free_id(struct bpf_prog * prog)2223e7895f01SPaul Moore void bpf_prog_free_id(struct bpf_prog *prog)
2224dc4bb0e2SMartin KaFai Lau {
2225d809e134SAlexei Starovoitov 	unsigned long flags;
2226d809e134SAlexei Starovoitov 
2227ad8ad79fSJakub Kicinski 	/* cBPF to eBPF migrations are currently not in the idr store.
2228ad8ad79fSJakub Kicinski 	 * Offloaded programs are removed from the store when their device
2229ad8ad79fSJakub Kicinski 	 * disappears - even if someone grabs an fd to them they are unusable,
2230ad8ad79fSJakub Kicinski 	 * simply waiting for refcnt to drop to be freed.
2231ad8ad79fSJakub Kicinski 	 */
2232dc4bb0e2SMartin KaFai Lau 	if (!prog->aux->id)
2233dc4bb0e2SMartin KaFai Lau 		return;
2234dc4bb0e2SMartin KaFai Lau 
2235d809e134SAlexei Starovoitov 	spin_lock_irqsave(&prog_idr_lock, flags);
2236dc4bb0e2SMartin KaFai Lau 	idr_remove(&prog_idr, prog->aux->id);
2237ad8ad79fSJakub Kicinski 	prog->aux->id = 0;
2238d809e134SAlexei Starovoitov 	spin_unlock_irqrestore(&prog_idr_lock, flags);
2239dc4bb0e2SMartin KaFai Lau }
2240dc4bb0e2SMartin KaFai Lau 
__bpf_prog_put_rcu(struct rcu_head * rcu)22411aacde3dSDaniel Borkmann static void __bpf_prog_put_rcu(struct rcu_head *rcu)
2242abf2e7d6SAlexei Starovoitov {
2243abf2e7d6SAlexei Starovoitov 	struct bpf_prog_aux *aux = container_of(rcu, struct bpf_prog_aux, rcu);
2244abf2e7d6SAlexei Starovoitov 
22453b4d9eb2SDaniel Borkmann 	kvfree(aux->func_info);
22468c1b6e69SAlexei Starovoitov 	kfree(aux->func_info_aux);
22473ac1f01bSRoman Gushchin 	free_uid(aux->user);
22481b67772eSAndrii Nakryiko 	security_bpf_prog_free(aux->prog);
2249abf2e7d6SAlexei Starovoitov 	bpf_prog_free(aux->prog);
2250abf2e7d6SAlexei Starovoitov }
2251abf2e7d6SAlexei Starovoitov 
__bpf_prog_put_noref(struct bpf_prog * prog,bool deferred)2252cd7455f1SDaniel Borkmann static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
2253cd7455f1SDaniel Borkmann {
2254cd7455f1SDaniel Borkmann 	bpf_prog_kallsyms_del_all(prog);
2255cd7455f1SDaniel Borkmann 	btf_put(prog->aux->btf);
225631bf1dbcSViktor Malik 	module_put(prog->aux->mod);
2257e16301fbSMartin KaFai Lau 	kvfree(prog->aux->jited_linfo);
2258e16301fbSMartin KaFai Lau 	kvfree(prog->aux->linfo);
2259e6ac2450SMartin KaFai Lau 	kfree(prog->aux->kfunc_tab);
226022dc4a0fSAndrii Nakryiko 	if (prog->aux->attach_btf)
226122dc4a0fSAndrii Nakryiko 		btf_put(prog->aux->attach_btf);
2262cd7455f1SDaniel Borkmann 
22631e6c62a8SAlexei Starovoitov 	if (deferred) {
226466c84731SAndrii Nakryiko 		if (prog->sleepable)
22651e6c62a8SAlexei Starovoitov 			call_rcu_tasks_trace(&prog->aux->rcu, __bpf_prog_put_rcu);
2266cd7455f1SDaniel Borkmann 		else
22671e6c62a8SAlexei Starovoitov 			call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
22681e6c62a8SAlexei Starovoitov 	} else {
2269cd7455f1SDaniel Borkmann 		__bpf_prog_put_rcu(&prog->aux->rcu);
2270cd7455f1SDaniel Borkmann 	}
22711e6c62a8SAlexei Starovoitov }
2272cd7455f1SDaniel Borkmann 
bpf_prog_put_deferred(struct work_struct * work)2273d809e134SAlexei Starovoitov static void bpf_prog_put_deferred(struct work_struct *work)
227409756af4SAlexei Starovoitov {
2275d809e134SAlexei Starovoitov 	struct bpf_prog_aux *aux;
2276d809e134SAlexei Starovoitov 	struct bpf_prog *prog;
2277d809e134SAlexei Starovoitov 
2278d809e134SAlexei Starovoitov 	aux = container_of(work, struct bpf_prog_aux, work);
2279d809e134SAlexei Starovoitov 	prog = aux->prog;
22806ee52e2aSSong Liu 	perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0);
2281bae141f5SDaniel Borkmann 	bpf_audit_prog(prog, BPF_AUDIT_UNLOAD);
2282e7895f01SPaul Moore 	bpf_prog_free_id(prog);
2283d809e134SAlexei Starovoitov 	__bpf_prog_put_noref(prog, true);
2284d809e134SAlexei Starovoitov }
2285d809e134SAlexei Starovoitov 
__bpf_prog_put(struct bpf_prog * prog)2286e7895f01SPaul Moore static void __bpf_prog_put(struct bpf_prog *prog)
2287d809e134SAlexei Starovoitov {
2288d809e134SAlexei Starovoitov 	struct bpf_prog_aux *aux = prog->aux;
2289d809e134SAlexei Starovoitov 
2290d809e134SAlexei Starovoitov 	if (atomic64_dec_and_test(&aux->refcnt)) {
2291d809e134SAlexei Starovoitov 		if (in_irq() || irqs_disabled()) {
2292d809e134SAlexei Starovoitov 			INIT_WORK(&aux->work, bpf_prog_put_deferred);
2293d809e134SAlexei Starovoitov 			schedule_work(&aux->work);
2294d809e134SAlexei Starovoitov 		} else {
2295d809e134SAlexei Starovoitov 			bpf_prog_put_deferred(&aux->work);
2296d809e134SAlexei Starovoitov 		}
229709756af4SAlexei Starovoitov 	}
2298a67edbf4SDaniel Borkmann }
2299b16d9aa4SMartin KaFai Lau 
bpf_prog_put(struct bpf_prog * prog)2300b16d9aa4SMartin KaFai Lau void bpf_prog_put(struct bpf_prog *prog)
2301b16d9aa4SMartin KaFai Lau {
2302e7895f01SPaul Moore 	__bpf_prog_put(prog);
2303b16d9aa4SMartin KaFai Lau }
2304e2e9b654SDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_put);
230509756af4SAlexei Starovoitov 
bpf_prog_release(struct inode * inode,struct file * filp)230609756af4SAlexei Starovoitov static int bpf_prog_release(struct inode *inode, struct file *filp)
230709756af4SAlexei Starovoitov {
230809756af4SAlexei Starovoitov 	struct bpf_prog *prog = filp->private_data;
230909756af4SAlexei Starovoitov 
23101aacde3dSDaniel Borkmann 	bpf_prog_put(prog);
231109756af4SAlexei Starovoitov 	return 0;
231209756af4SAlexei Starovoitov }
231309756af4SAlexei Starovoitov 
231461a0abaeSEric Dumazet struct bpf_prog_kstats {
231561a0abaeSEric Dumazet 	u64 nsecs;
231661a0abaeSEric Dumazet 	u64 cnt;
231761a0abaeSEric Dumazet 	u64 misses;
231861a0abaeSEric Dumazet };
231961a0abaeSEric Dumazet 
bpf_prog_inc_misses_counter(struct bpf_prog * prog)232005b24ff9SJiri Olsa void notrace bpf_prog_inc_misses_counter(struct bpf_prog *prog)
232105b24ff9SJiri Olsa {
232205b24ff9SJiri Olsa 	struct bpf_prog_stats *stats;
232305b24ff9SJiri Olsa 	unsigned int flags;
232405b24ff9SJiri Olsa 
232505b24ff9SJiri Olsa 	stats = this_cpu_ptr(prog->stats);
232605b24ff9SJiri Olsa 	flags = u64_stats_update_begin_irqsave(&stats->syncp);
232705b24ff9SJiri Olsa 	u64_stats_inc(&stats->misses);
232805b24ff9SJiri Olsa 	u64_stats_update_end_irqrestore(&stats->syncp, flags);
232905b24ff9SJiri Olsa }
233005b24ff9SJiri Olsa 
bpf_prog_get_stats(const struct bpf_prog * prog,struct bpf_prog_kstats * stats)2331492ecee8SAlexei Starovoitov static void bpf_prog_get_stats(const struct bpf_prog *prog,
233261a0abaeSEric Dumazet 			       struct bpf_prog_kstats *stats)
2333492ecee8SAlexei Starovoitov {
23349ed9e9baSAlexei Starovoitov 	u64 nsecs = 0, cnt = 0, misses = 0;
2335492ecee8SAlexei Starovoitov 	int cpu;
2336492ecee8SAlexei Starovoitov 
2337492ecee8SAlexei Starovoitov 	for_each_possible_cpu(cpu) {
2338492ecee8SAlexei Starovoitov 		const struct bpf_prog_stats *st;
2339492ecee8SAlexei Starovoitov 		unsigned int start;
23409ed9e9baSAlexei Starovoitov 		u64 tnsecs, tcnt, tmisses;
2341492ecee8SAlexei Starovoitov 
2342700d4796SAlexei Starovoitov 		st = per_cpu_ptr(prog->stats, cpu);
2343492ecee8SAlexei Starovoitov 		do {
234497c4090bSThomas Gleixner 			start = u64_stats_fetch_begin(&st->syncp);
234561a0abaeSEric Dumazet 			tnsecs = u64_stats_read(&st->nsecs);
234661a0abaeSEric Dumazet 			tcnt = u64_stats_read(&st->cnt);
234761a0abaeSEric Dumazet 			tmisses = u64_stats_read(&st->misses);
234897c4090bSThomas Gleixner 		} while (u64_stats_fetch_retry(&st->syncp, start));
2349492ecee8SAlexei Starovoitov 		nsecs += tnsecs;
2350492ecee8SAlexei Starovoitov 		cnt += tcnt;
23519ed9e9baSAlexei Starovoitov 		misses += tmisses;
2352492ecee8SAlexei Starovoitov 	}
2353492ecee8SAlexei Starovoitov 	stats->nsecs = nsecs;
2354492ecee8SAlexei Starovoitov 	stats->cnt = cnt;
23559ed9e9baSAlexei Starovoitov 	stats->misses = misses;
2356492ecee8SAlexei Starovoitov }
2357492ecee8SAlexei Starovoitov 
23587bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
bpf_prog_show_fdinfo(struct seq_file * m,struct file * filp)23597bd509e3SDaniel Borkmann static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp)
23607bd509e3SDaniel Borkmann {
23617bd509e3SDaniel Borkmann 	const struct bpf_prog *prog = filp->private_data;
2362f1f7714eSDaniel Borkmann 	char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
236361a0abaeSEric Dumazet 	struct bpf_prog_kstats stats;
23647bd509e3SDaniel Borkmann 
2365492ecee8SAlexei Starovoitov 	bpf_prog_get_stats(prog, &stats);
2366f1f7714eSDaniel Borkmann 	bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
23677bd509e3SDaniel Borkmann 	seq_printf(m,
23687bd509e3SDaniel Borkmann 		   "prog_type:\t%u\n"
23697bd509e3SDaniel Borkmann 		   "prog_jited:\t%u\n"
2370f1f7714eSDaniel Borkmann 		   "prog_tag:\t%s\n"
23714316b409SDaniel Borkmann 		   "memlock:\t%llu\n"
2372492ecee8SAlexei Starovoitov 		   "prog_id:\t%u\n"
2373492ecee8SAlexei Starovoitov 		   "run_time_ns:\t%llu\n"
23749ed9e9baSAlexei Starovoitov 		   "run_cnt:\t%llu\n"
2375aba64c7dSDave Marchevsky 		   "recursion_misses:\t%llu\n"
2376aba64c7dSDave Marchevsky 		   "verified_insns:\t%u\n",
23777bd509e3SDaniel Borkmann 		   prog->type,
23787bd509e3SDaniel Borkmann 		   prog->jited,
2379f1f7714eSDaniel Borkmann 		   prog_tag,
23804316b409SDaniel Borkmann 		   prog->pages * 1ULL << PAGE_SHIFT,
2381492ecee8SAlexei Starovoitov 		   prog->aux->id,
2382492ecee8SAlexei Starovoitov 		   stats.nsecs,
23839ed9e9baSAlexei Starovoitov 		   stats.cnt,
2384aba64c7dSDave Marchevsky 		   stats.misses,
2385aba64c7dSDave Marchevsky 		   prog->aux->verified_insns);
23867bd509e3SDaniel Borkmann }
23877bd509e3SDaniel Borkmann #endif
23887bd509e3SDaniel Borkmann 
2389f66e448cSChenbo Feng const struct file_operations bpf_prog_fops = {
23907bd509e3SDaniel Borkmann #ifdef CONFIG_PROC_FS
23917bd509e3SDaniel Borkmann 	.show_fdinfo	= bpf_prog_show_fdinfo,
23927bd509e3SDaniel Borkmann #endif
239309756af4SAlexei Starovoitov 	.release	= bpf_prog_release,
23946e71b04aSChenbo Feng 	.read		= bpf_dummy_read,
23956e71b04aSChenbo Feng 	.write		= bpf_dummy_write,
239609756af4SAlexei Starovoitov };
239709756af4SAlexei Starovoitov 
bpf_prog_new_fd(struct bpf_prog * prog)2398b2197755SDaniel Borkmann int bpf_prog_new_fd(struct bpf_prog *prog)
2399aa79781bSDaniel Borkmann {
2400afdb09c7SChenbo Feng 	int ret;
2401afdb09c7SChenbo Feng 
2402afdb09c7SChenbo Feng 	ret = security_bpf_prog(prog);
2403afdb09c7SChenbo Feng 	if (ret < 0)
2404afdb09c7SChenbo Feng 		return ret;
2405afdb09c7SChenbo Feng 
2406aa79781bSDaniel Borkmann 	return anon_inode_getfd("bpf-prog", &bpf_prog_fops, prog,
2407aa79781bSDaniel Borkmann 				O_RDWR | O_CLOEXEC);
2408aa79781bSDaniel Borkmann }
2409aa79781bSDaniel Borkmann 
____bpf_prog_get(struct fd f)2410113214beSDaniel Borkmann static struct bpf_prog *____bpf_prog_get(struct fd f)
241109756af4SAlexei Starovoitov {
241209756af4SAlexei Starovoitov 	if (!f.file)
241309756af4SAlexei Starovoitov 		return ERR_PTR(-EBADF);
241409756af4SAlexei Starovoitov 	if (f.file->f_op != &bpf_prog_fops) {
241509756af4SAlexei Starovoitov 		fdput(f);
241609756af4SAlexei Starovoitov 		return ERR_PTR(-EINVAL);
241709756af4SAlexei Starovoitov 	}
241809756af4SAlexei Starovoitov 
2419c2101297SDaniel Borkmann 	return f.file->private_data;
242009756af4SAlexei Starovoitov }
242109756af4SAlexei Starovoitov 
bpf_prog_add(struct bpf_prog * prog,int i)242285192dbfSAndrii Nakryiko void bpf_prog_add(struct bpf_prog *prog, int i)
242392117d84SAlexei Starovoitov {
242485192dbfSAndrii Nakryiko 	atomic64_add(i, &prog->aux->refcnt);
242592117d84SAlexei Starovoitov }
242659d3656dSBrenden Blanco EXPORT_SYMBOL_GPL(bpf_prog_add);
242759d3656dSBrenden Blanco 
bpf_prog_sub(struct bpf_prog * prog,int i)2428c540594fSDaniel Borkmann void bpf_prog_sub(struct bpf_prog *prog, int i)
2429c540594fSDaniel Borkmann {
2430c540594fSDaniel Borkmann 	/* Only to be used for undoing previous bpf_prog_add() in some
2431c540594fSDaniel Borkmann 	 * error path. We still know that another entity in our call
2432c540594fSDaniel Borkmann 	 * path holds a reference to the program, thus atomic_sub() can
2433c540594fSDaniel Borkmann 	 * be safely used in such cases!
2434c540594fSDaniel Borkmann 	 */
243585192dbfSAndrii Nakryiko 	WARN_ON(atomic64_sub_return(i, &prog->aux->refcnt) == 0);
2436c540594fSDaniel Borkmann }
2437c540594fSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_sub);
2438c540594fSDaniel Borkmann 
bpf_prog_inc(struct bpf_prog * prog)243985192dbfSAndrii Nakryiko void bpf_prog_inc(struct bpf_prog *prog)
244059d3656dSBrenden Blanco {
244185192dbfSAndrii Nakryiko 	atomic64_inc(&prog->aux->refcnt);
244259d3656dSBrenden Blanco }
244397bc402dSDaniel Borkmann EXPORT_SYMBOL_GPL(bpf_prog_inc);
244492117d84SAlexei Starovoitov 
2445b16d9aa4SMartin KaFai Lau /* prog_idr_lock should have been held */
bpf_prog_inc_not_zero(struct bpf_prog * prog)2446a6f6df69SJohn Fastabend struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog)
2447b16d9aa4SMartin KaFai Lau {
2448b16d9aa4SMartin KaFai Lau 	int refold;
2449b16d9aa4SMartin KaFai Lau 
245085192dbfSAndrii Nakryiko 	refold = atomic64_fetch_add_unless(&prog->aux->refcnt, 1, 0);
2451b16d9aa4SMartin KaFai Lau 
2452b16d9aa4SMartin KaFai Lau 	if (!refold)
2453b16d9aa4SMartin KaFai Lau 		return ERR_PTR(-ENOENT);
2454b16d9aa4SMartin KaFai Lau 
2455b16d9aa4SMartin KaFai Lau 	return prog;
2456b16d9aa4SMartin KaFai Lau }
2457a6f6df69SJohn Fastabend EXPORT_SYMBOL_GPL(bpf_prog_inc_not_zero);
2458b16d9aa4SMartin KaFai Lau 
bpf_prog_get_ok(struct bpf_prog * prog,enum bpf_prog_type * attach_type,bool attach_drv)2459040ee692SAl Viro bool bpf_prog_get_ok(struct bpf_prog *prog,
2460288b3de5SJakub Kicinski 			    enum bpf_prog_type *attach_type, bool attach_drv)
2461248f346fSJakub Kicinski {
2462288b3de5SJakub Kicinski 	/* not an attachment, just a refcount inc, always allow */
2463288b3de5SJakub Kicinski 	if (!attach_type)
2464288b3de5SJakub Kicinski 		return true;
2465248f346fSJakub Kicinski 
2466248f346fSJakub Kicinski 	if (prog->type != *attach_type)
2467248f346fSJakub Kicinski 		return false;
24689d03ebc7SStanislav Fomichev 	if (bpf_prog_is_offloaded(prog->aux) && !attach_drv)
2469248f346fSJakub Kicinski 		return false;
2470248f346fSJakub Kicinski 
2471248f346fSJakub Kicinski 	return true;
2472248f346fSJakub Kicinski }
2473248f346fSJakub Kicinski 
__bpf_prog_get(u32 ufd,enum bpf_prog_type * attach_type,bool attach_drv)2474248f346fSJakub Kicinski static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type,
2475288b3de5SJakub Kicinski 				       bool attach_drv)
247609756af4SAlexei Starovoitov {
247709756af4SAlexei Starovoitov 	struct fd f = fdget(ufd);
247809756af4SAlexei Starovoitov 	struct bpf_prog *prog;
247909756af4SAlexei Starovoitov 
2480113214beSDaniel Borkmann 	prog = ____bpf_prog_get(f);
248109756af4SAlexei Starovoitov 	if (IS_ERR(prog))
248209756af4SAlexei Starovoitov 		return prog;
2483288b3de5SJakub Kicinski 	if (!bpf_prog_get_ok(prog, attach_type, attach_drv)) {
2484113214beSDaniel Borkmann 		prog = ERR_PTR(-EINVAL);
2485113214beSDaniel Borkmann 		goto out;
2486113214beSDaniel Borkmann 	}
248709756af4SAlexei Starovoitov 
248885192dbfSAndrii Nakryiko 	bpf_prog_inc(prog);
2489113214beSDaniel Borkmann out:
249009756af4SAlexei Starovoitov 	fdput(f);
249109756af4SAlexei Starovoitov 	return prog;
249209756af4SAlexei Starovoitov }
2493113214beSDaniel Borkmann 
bpf_prog_get(u32 ufd)2494113214beSDaniel Borkmann struct bpf_prog *bpf_prog_get(u32 ufd)
2495113214beSDaniel Borkmann {
2496288b3de5SJakub Kicinski 	return __bpf_prog_get(ufd, NULL, false);
2497113214beSDaniel Borkmann }
2498113214beSDaniel Borkmann 
bpf_prog_get_type_dev(u32 ufd,enum bpf_prog_type type,bool attach_drv)2499248f346fSJakub Kicinski struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type,
2500288b3de5SJakub Kicinski 				       bool attach_drv)
2501248f346fSJakub Kicinski {
25024d220ed0SAlexei Starovoitov 	return __bpf_prog_get(ufd, &type, attach_drv);
2503248f346fSJakub Kicinski }
25046c8dfe21SJakub Kicinski EXPORT_SYMBOL_GPL(bpf_prog_get_type_dev);
2505248f346fSJakub Kicinski 
2506aac3fc32SAndrey Ignatov /* Initially all BPF programs could be loaded w/o specifying
2507aac3fc32SAndrey Ignatov  * expected_attach_type. Later for some of them specifying expected_attach_type
2508aac3fc32SAndrey Ignatov  * at load time became required so that program could be validated properly.
2509aac3fc32SAndrey Ignatov  * Programs of types that are allowed to be loaded both w/ and w/o (for
2510aac3fc32SAndrey Ignatov  * backward compatibility) expected_attach_type, should have the default attach
2511aac3fc32SAndrey Ignatov  * type assigned to expected_attach_type for the latter case, so that it can be
2512aac3fc32SAndrey Ignatov  * validated later at attach time.
2513aac3fc32SAndrey Ignatov  *
2514aac3fc32SAndrey Ignatov  * bpf_prog_load_fixup_attach_type() sets expected_attach_type in @attr if
2515aac3fc32SAndrey Ignatov  * prog type requires it but has some attach types that have to be backward
2516aac3fc32SAndrey Ignatov  * compatible.
2517aac3fc32SAndrey Ignatov  */
bpf_prog_load_fixup_attach_type(union bpf_attr * attr)2518aac3fc32SAndrey Ignatov static void bpf_prog_load_fixup_attach_type(union bpf_attr *attr)
2519aac3fc32SAndrey Ignatov {
2520aac3fc32SAndrey Ignatov 	switch (attr->prog_type) {
2521aac3fc32SAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK:
2522aac3fc32SAndrey Ignatov 		/* Unfortunately BPF_ATTACH_TYPE_UNSPEC enumeration doesn't
2523aac3fc32SAndrey Ignatov 		 * exist so checking for non-zero is the way to go here.
2524aac3fc32SAndrey Ignatov 		 */
2525aac3fc32SAndrey Ignatov 		if (!attr->expected_attach_type)
2526aac3fc32SAndrey Ignatov 			attr->expected_attach_type =
2527aac3fc32SAndrey Ignatov 				BPF_CGROUP_INET_SOCK_CREATE;
2528aac3fc32SAndrey Ignatov 		break;
2529d5e4ddaeSKuniyuki Iwashima 	case BPF_PROG_TYPE_SK_REUSEPORT:
2530d5e4ddaeSKuniyuki Iwashima 		if (!attr->expected_attach_type)
2531d5e4ddaeSKuniyuki Iwashima 			attr->expected_attach_type =
2532d5e4ddaeSKuniyuki Iwashima 				BPF_SK_REUSEPORT_SELECT;
2533d5e4ddaeSKuniyuki Iwashima 		break;
2534aac3fc32SAndrey Ignatov 	}
2535aac3fc32SAndrey Ignatov }
2536aac3fc32SAndrey Ignatov 
25375e43f899SAndrey Ignatov static int
bpf_prog_load_check_attach(enum bpf_prog_type prog_type,enum bpf_attach_type expected_attach_type,struct btf * attach_btf,u32 btf_id,struct bpf_prog * dst_prog)2538ccfe29ebSAlexei Starovoitov bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
2539ccfe29ebSAlexei Starovoitov 			   enum bpf_attach_type expected_attach_type,
2540290248a5SAndrii Nakryiko 			   struct btf *attach_btf, u32 btf_id,
2541290248a5SAndrii Nakryiko 			   struct bpf_prog *dst_prog)
25425e43f899SAndrey Ignatov {
254327ae7997SMartin KaFai Lau 	if (btf_id) {
2544c108e3c1SAlexei Starovoitov 		if (btf_id > BTF_MAX_TYPE)
2545c108e3c1SAlexei Starovoitov 			return -EINVAL;
254627ae7997SMartin KaFai Lau 
2547290248a5SAndrii Nakryiko 		if (!attach_btf && !dst_prog)
2548290248a5SAndrii Nakryiko 			return -EINVAL;
2549290248a5SAndrii Nakryiko 
255027ae7997SMartin KaFai Lau 		switch (prog_type) {
255127ae7997SMartin KaFai Lau 		case BPF_PROG_TYPE_TRACING:
25529e4e01dfSKP Singh 		case BPF_PROG_TYPE_LSM:
255327ae7997SMartin KaFai Lau 		case BPF_PROG_TYPE_STRUCT_OPS:
2554be8704ffSAlexei Starovoitov 		case BPF_PROG_TYPE_EXT:
2555c108e3c1SAlexei Starovoitov 			break;
2556c108e3c1SAlexei Starovoitov 		default:
2557c108e3c1SAlexei Starovoitov 			return -EINVAL;
2558c108e3c1SAlexei Starovoitov 		}
255927ae7997SMartin KaFai Lau 	}
256027ae7997SMartin KaFai Lau 
2561290248a5SAndrii Nakryiko 	if (attach_btf && (!btf_id || dst_prog))
2562290248a5SAndrii Nakryiko 		return -EINVAL;
2563290248a5SAndrii Nakryiko 
2564290248a5SAndrii Nakryiko 	if (dst_prog && prog_type != BPF_PROG_TYPE_TRACING &&
2565be8704ffSAlexei Starovoitov 	    prog_type != BPF_PROG_TYPE_EXT)
256627ae7997SMartin KaFai Lau 		return -EINVAL;
2567c108e3c1SAlexei Starovoitov 
2568c108e3c1SAlexei Starovoitov 	switch (prog_type) {
2569aac3fc32SAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK:
2570aac3fc32SAndrey Ignatov 		switch (expected_attach_type) {
2571aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET_SOCK_CREATE:
2572f5836749SStanislav Fomichev 		case BPF_CGROUP_INET_SOCK_RELEASE:
2573aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET4_POST_BIND:
2574aac3fc32SAndrey Ignatov 		case BPF_CGROUP_INET6_POST_BIND:
2575aac3fc32SAndrey Ignatov 			return 0;
2576aac3fc32SAndrey Ignatov 		default:
2577aac3fc32SAndrey Ignatov 			return -EINVAL;
2578aac3fc32SAndrey Ignatov 		}
25794fbac77dSAndrey Ignatov 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
25804fbac77dSAndrey Ignatov 		switch (expected_attach_type) {
25814fbac77dSAndrey Ignatov 		case BPF_CGROUP_INET4_BIND:
25824fbac77dSAndrey Ignatov 		case BPF_CGROUP_INET6_BIND:
2583d74bad4eSAndrey Ignatov 		case BPF_CGROUP_INET4_CONNECT:
2584d74bad4eSAndrey Ignatov 		case BPF_CGROUP_INET6_CONNECT:
2585859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_CONNECT:
25861b66d253SDaniel Borkmann 		case BPF_CGROUP_INET4_GETPEERNAME:
25871b66d253SDaniel Borkmann 		case BPF_CGROUP_INET6_GETPEERNAME:
2588859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_GETPEERNAME:
25891b66d253SDaniel Borkmann 		case BPF_CGROUP_INET4_GETSOCKNAME:
25901b66d253SDaniel Borkmann 		case BPF_CGROUP_INET6_GETSOCKNAME:
2591859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_GETSOCKNAME:
25921cedee13SAndrey Ignatov 		case BPF_CGROUP_UDP4_SENDMSG:
25931cedee13SAndrey Ignatov 		case BPF_CGROUP_UDP6_SENDMSG:
2594859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_SENDMSG:
2595983695faSDaniel Borkmann 		case BPF_CGROUP_UDP4_RECVMSG:
2596983695faSDaniel Borkmann 		case BPF_CGROUP_UDP6_RECVMSG:
2597859051ddSDaan De Meyer 		case BPF_CGROUP_UNIX_RECVMSG:
25985e43f899SAndrey Ignatov 			return 0;
25994fbac77dSAndrey Ignatov 		default:
26004fbac77dSAndrey Ignatov 			return -EINVAL;
26014fbac77dSAndrey Ignatov 		}
26025cf1e914Sbrakmo 	case BPF_PROG_TYPE_CGROUP_SKB:
26035cf1e914Sbrakmo 		switch (expected_attach_type) {
26045cf1e914Sbrakmo 		case BPF_CGROUP_INET_INGRESS:
26055cf1e914Sbrakmo 		case BPF_CGROUP_INET_EGRESS:
26065cf1e914Sbrakmo 			return 0;
26075cf1e914Sbrakmo 		default:
26085cf1e914Sbrakmo 			return -EINVAL;
26095cf1e914Sbrakmo 		}
26100d01da6aSStanislav Fomichev 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
26110d01da6aSStanislav Fomichev 		switch (expected_attach_type) {
26120d01da6aSStanislav Fomichev 		case BPF_CGROUP_SETSOCKOPT:
26130d01da6aSStanislav Fomichev 		case BPF_CGROUP_GETSOCKOPT:
26140d01da6aSStanislav Fomichev 			return 0;
26150d01da6aSStanislav Fomichev 		default:
26160d01da6aSStanislav Fomichev 			return -EINVAL;
26170d01da6aSStanislav Fomichev 		}
2618e9ddbb77SJakub Sitnicki 	case BPF_PROG_TYPE_SK_LOOKUP:
2619e9ddbb77SJakub Sitnicki 		if (expected_attach_type == BPF_SK_LOOKUP)
2620e9ddbb77SJakub Sitnicki 			return 0;
2621e9ddbb77SJakub Sitnicki 		return -EINVAL;
2622d5e4ddaeSKuniyuki Iwashima 	case BPF_PROG_TYPE_SK_REUSEPORT:
2623d5e4ddaeSKuniyuki Iwashima 		switch (expected_attach_type) {
2624d5e4ddaeSKuniyuki Iwashima 		case BPF_SK_REUSEPORT_SELECT:
2625d5e4ddaeSKuniyuki Iwashima 		case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE:
2626d5e4ddaeSKuniyuki Iwashima 			return 0;
2627d5e4ddaeSKuniyuki Iwashima 		default:
2628d5e4ddaeSKuniyuki Iwashima 			return -EINVAL;
2629d5e4ddaeSKuniyuki Iwashima 		}
2630132328e8SFlorian Westphal 	case BPF_PROG_TYPE_NETFILTER:
2631132328e8SFlorian Westphal 		if (expected_attach_type == BPF_NETFILTER)
2632132328e8SFlorian Westphal 			return 0;
2633132328e8SFlorian Westphal 		return -EINVAL;
263479a7f8bdSAlexei Starovoitov 	case BPF_PROG_TYPE_SYSCALL:
2635be8704ffSAlexei Starovoitov 	case BPF_PROG_TYPE_EXT:
2636be8704ffSAlexei Starovoitov 		if (expected_attach_type)
2637be8704ffSAlexei Starovoitov 			return -EINVAL;
2638df561f66SGustavo A. R. Silva 		fallthrough;
26394fbac77dSAndrey Ignatov 	default:
26404fbac77dSAndrey Ignatov 		return 0;
26414fbac77dSAndrey Ignatov 	}
26425e43f899SAndrey Ignatov }
26435e43f899SAndrey Ignatov 
is_net_admin_prog_type(enum bpf_prog_type prog_type)26442c78ee89SAlexei Starovoitov static bool is_net_admin_prog_type(enum bpf_prog_type prog_type)
26452c78ee89SAlexei Starovoitov {
26462c78ee89SAlexei Starovoitov 	switch (prog_type) {
26472c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SCHED_CLS:
26482c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SCHED_ACT:
26492c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_XDP:
26502c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_IN:
26512c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_OUT:
26522c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_XMIT:
26532c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LWT_SEG6LOCAL:
26542c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_SKB:
26552c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_MSG:
26562c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
26572c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_DEVICE:
26582c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCK:
26592c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
26602c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
26612c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
26622c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SOCK_OPS:
26632c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_EXT: /* extends any prog */
266484601d6eSFlorian Westphal 	case BPF_PROG_TYPE_NETFILTER:
26652c78ee89SAlexei Starovoitov 		return true;
26662c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_CGROUP_SKB:
26672c78ee89SAlexei Starovoitov 		/* always unpriv */
26682c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_SK_REUSEPORT:
26692c78ee89SAlexei Starovoitov 		/* equivalent to SOCKET_FILTER. need CAP_BPF only */
26702c78ee89SAlexei Starovoitov 	default:
26712c78ee89SAlexei Starovoitov 		return false;
26722c78ee89SAlexei Starovoitov 	}
26732c78ee89SAlexei Starovoitov }
26742c78ee89SAlexei Starovoitov 
is_perfmon_prog_type(enum bpf_prog_type prog_type)26752c78ee89SAlexei Starovoitov static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
26762c78ee89SAlexei Starovoitov {
26772c78ee89SAlexei Starovoitov 	switch (prog_type) {
26782c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_KPROBE:
26792c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_TRACEPOINT:
26802c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_PERF_EVENT:
26812c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_RAW_TRACEPOINT:
26822c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
26832c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_TRACING:
26842c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_LSM:
26852c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_STRUCT_OPS: /* has access to struct sock */
26862c78ee89SAlexei Starovoitov 	case BPF_PROG_TYPE_EXT: /* extends any prog */
26872c78ee89SAlexei Starovoitov 		return true;
26882c78ee89SAlexei Starovoitov 	default:
26892c78ee89SAlexei Starovoitov 		return false;
26902c78ee89SAlexei Starovoitov 	}
26912c78ee89SAlexei Starovoitov }
26922c78ee89SAlexei Starovoitov 
269309756af4SAlexei Starovoitov /* last field in 'union bpf_attr' used by this command */
2694caf8f28eSAndrii Nakryiko #define BPF_PROG_LOAD_LAST_FIELD prog_token_fd
269509756af4SAlexei Starovoitov 
bpf_prog_load(union bpf_attr * attr,bpfptr_t uattr,u32 uattr_size)269647a71c1fSAndrii Nakryiko static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
269709756af4SAlexei Starovoitov {
269809756af4SAlexei Starovoitov 	enum bpf_prog_type type = attr->prog_type;
2699290248a5SAndrii Nakryiko 	struct bpf_prog *prog, *dst_prog = NULL;
2700290248a5SAndrii Nakryiko 	struct btf *attach_btf = NULL;
2701caf8f28eSAndrii Nakryiko 	struct bpf_token *token = NULL;
2702caf8f28eSAndrii Nakryiko 	bool bpf_cap;
270309756af4SAlexei Starovoitov 	int err;
270409756af4SAlexei Starovoitov 	char license[128];
270509756af4SAlexei Starovoitov 
270609756af4SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_LOAD))
270709756af4SAlexei Starovoitov 		return -EINVAL;
270809756af4SAlexei Starovoitov 
2709c240eff6SJiong Wang 	if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT |
2710c240eff6SJiong Wang 				 BPF_F_ANY_ALIGNMENT |
271110d274e8SAlexei Starovoitov 				 BPF_F_TEST_STATE_FREQ |
27121e6c62a8SAlexei Starovoitov 				 BPF_F_SLEEPABLE |
2713c2f2cdbeSLorenzo Bianconi 				 BPF_F_TEST_RND_HI32 |
27142b3486bcSStanislav Fomichev 				 BPF_F_XDP_HAS_FRAGS |
27155f99f312SAndrii Nakryiko 				 BPF_F_XDP_DEV_BOUND_ONLY |
2716caf8f28eSAndrii Nakryiko 				 BPF_F_TEST_REG_INVARIANTS |
2717caf8f28eSAndrii Nakryiko 				 BPF_F_TOKEN_FD))
2718e07b98d9SDavid S. Miller 		return -EINVAL;
2719e07b98d9SDavid S. Miller 
2720caf8f28eSAndrii Nakryiko 	bpf_prog_load_fixup_attach_type(attr);
2721caf8f28eSAndrii Nakryiko 
2722caf8f28eSAndrii Nakryiko 	if (attr->prog_flags & BPF_F_TOKEN_FD) {
2723caf8f28eSAndrii Nakryiko 		token = bpf_token_get_from_fd(attr->prog_token_fd);
2724caf8f28eSAndrii Nakryiko 		if (IS_ERR(token))
2725caf8f28eSAndrii Nakryiko 			return PTR_ERR(token);
2726caf8f28eSAndrii Nakryiko 		/* if current token doesn't grant prog loading permissions,
2727caf8f28eSAndrii Nakryiko 		 * then we can't use this token, so ignore it and rely on
2728caf8f28eSAndrii Nakryiko 		 * system-wide capabilities checks
2729caf8f28eSAndrii Nakryiko 		 */
2730caf8f28eSAndrii Nakryiko 		if (!bpf_token_allow_cmd(token, BPF_PROG_LOAD) ||
2731caf8f28eSAndrii Nakryiko 		    !bpf_token_allow_prog_type(token, attr->prog_type,
2732caf8f28eSAndrii Nakryiko 					       attr->expected_attach_type)) {
2733caf8f28eSAndrii Nakryiko 			bpf_token_put(token);
2734caf8f28eSAndrii Nakryiko 			token = NULL;
2735caf8f28eSAndrii Nakryiko 		}
2736caf8f28eSAndrii Nakryiko 	}
2737caf8f28eSAndrii Nakryiko 
2738caf8f28eSAndrii Nakryiko 	bpf_cap = bpf_token_capable(token, CAP_BPF);
2739caf8f28eSAndrii Nakryiko 	err = -EPERM;
2740caf8f28eSAndrii Nakryiko 
2741e9ee9efcSDavid Miller 	if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
2742e9ee9efcSDavid Miller 	    (attr->prog_flags & BPF_F_ANY_ALIGNMENT) &&
2743caf8f28eSAndrii Nakryiko 	    !bpf_cap)
2744caf8f28eSAndrii Nakryiko 		goto put_token;
2745e9ee9efcSDavid Miller 
27461d28635aSAndrii Nakryiko 	/* Intent here is for unprivileged_bpf_disabled to block BPF program
27471d28635aSAndrii Nakryiko 	 * creation for unprivileged users; other actions depend
27481d28635aSAndrii Nakryiko 	 * on fd availability and access to bpffs, so are dependent on
27491d28635aSAndrii Nakryiko 	 * object creation success. Even with unprivileged BPF disabled,
27501d28635aSAndrii Nakryiko 	 * capability checks are still carried out for these
27511d28635aSAndrii Nakryiko 	 * and other operations.
27521d28635aSAndrii Nakryiko 	 */
2753caf8f28eSAndrii Nakryiko 	if (sysctl_unprivileged_bpf_disabled && !bpf_cap)
2754caf8f28eSAndrii Nakryiko 		goto put_token;
275509756af4SAlexei Starovoitov 
2756c04c0d2bSAlexei Starovoitov 	if (attr->insn_cnt == 0 ||
2757caf8f28eSAndrii Nakryiko 	    attr->insn_cnt > (bpf_cap ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) {
2758caf8f28eSAndrii Nakryiko 		err = -E2BIG;
2759caf8f28eSAndrii Nakryiko 		goto put_token;
2760caf8f28eSAndrii Nakryiko 	}
276180b7d819SChenbo Feng 	if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
276280b7d819SChenbo Feng 	    type != BPF_PROG_TYPE_CGROUP_SKB &&
2763caf8f28eSAndrii Nakryiko 	    !bpf_cap)
2764caf8f28eSAndrii Nakryiko 		goto put_token;
27652c78ee89SAlexei Starovoitov 
2766caf8f28eSAndrii Nakryiko 	if (is_net_admin_prog_type(type) && !bpf_token_capable(token, CAP_NET_ADMIN))
2767caf8f28eSAndrii Nakryiko 		goto put_token;
2768caf8f28eSAndrii Nakryiko 	if (is_perfmon_prog_type(type) && !bpf_token_capable(token, CAP_PERFMON))
2769caf8f28eSAndrii Nakryiko 		goto put_token;
27701be7f75dSAlexei Starovoitov 
2771290248a5SAndrii Nakryiko 	/* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog
2772290248a5SAndrii Nakryiko 	 * or btf, we need to check which one it is
2773290248a5SAndrii Nakryiko 	 */
2774290248a5SAndrii Nakryiko 	if (attr->attach_prog_fd) {
2775290248a5SAndrii Nakryiko 		dst_prog = bpf_prog_get(attr->attach_prog_fd);
2776290248a5SAndrii Nakryiko 		if (IS_ERR(dst_prog)) {
2777290248a5SAndrii Nakryiko 			dst_prog = NULL;
2778290248a5SAndrii Nakryiko 			attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd);
2779caf8f28eSAndrii Nakryiko 			if (IS_ERR(attach_btf)) {
2780caf8f28eSAndrii Nakryiko 				err = -EINVAL;
2781caf8f28eSAndrii Nakryiko 				goto put_token;
2782caf8f28eSAndrii Nakryiko 			}
2783290248a5SAndrii Nakryiko 			if (!btf_is_kernel(attach_btf)) {
27848bdd8e27SAndrii Nakryiko 				/* attaching through specifying bpf_prog's BTF
27858bdd8e27SAndrii Nakryiko 				 * objects directly might be supported eventually
27868bdd8e27SAndrii Nakryiko 				 */
2787290248a5SAndrii Nakryiko 				btf_put(attach_btf);
2788caf8f28eSAndrii Nakryiko 				err = -ENOTSUPP;
2789caf8f28eSAndrii Nakryiko 				goto put_token;
2790290248a5SAndrii Nakryiko 			}
2791290248a5SAndrii Nakryiko 		}
2792290248a5SAndrii Nakryiko 	} else if (attr->attach_btf_id) {
2793290248a5SAndrii Nakryiko 		/* fall back to vmlinux BTF, if BTF type ID is specified */
2794290248a5SAndrii Nakryiko 		attach_btf = bpf_get_btf_vmlinux();
2795caf8f28eSAndrii Nakryiko 		if (IS_ERR(attach_btf)) {
2796caf8f28eSAndrii Nakryiko 			err = PTR_ERR(attach_btf);
2797caf8f28eSAndrii Nakryiko 			goto put_token;
2798caf8f28eSAndrii Nakryiko 		}
2799caf8f28eSAndrii Nakryiko 		if (!attach_btf) {
2800caf8f28eSAndrii Nakryiko 			err = -EINVAL;
2801caf8f28eSAndrii Nakryiko 			goto put_token;
2802caf8f28eSAndrii Nakryiko 		}
2803290248a5SAndrii Nakryiko 		btf_get(attach_btf);
2804290248a5SAndrii Nakryiko 	}
2805290248a5SAndrii Nakryiko 
2806ccfe29ebSAlexei Starovoitov 	if (bpf_prog_load_check_attach(type, attr->expected_attach_type,
2807290248a5SAndrii Nakryiko 				       attach_btf, attr->attach_btf_id,
2808290248a5SAndrii Nakryiko 				       dst_prog)) {
2809290248a5SAndrii Nakryiko 		if (dst_prog)
2810290248a5SAndrii Nakryiko 			bpf_prog_put(dst_prog);
2811290248a5SAndrii Nakryiko 		if (attach_btf)
2812290248a5SAndrii Nakryiko 			btf_put(attach_btf);
2813caf8f28eSAndrii Nakryiko 		err = -EINVAL;
2814caf8f28eSAndrii Nakryiko 		goto put_token;
2815290248a5SAndrii Nakryiko 	}
28165e43f899SAndrey Ignatov 
281709756af4SAlexei Starovoitov 	/* plain bpf_prog allocation */
281809756af4SAlexei Starovoitov 	prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER);
2819290248a5SAndrii Nakryiko 	if (!prog) {
2820290248a5SAndrii Nakryiko 		if (dst_prog)
2821290248a5SAndrii Nakryiko 			bpf_prog_put(dst_prog);
2822290248a5SAndrii Nakryiko 		if (attach_btf)
2823290248a5SAndrii Nakryiko 			btf_put(attach_btf);
2824caf8f28eSAndrii Nakryiko 		err = -EINVAL;
2825caf8f28eSAndrii Nakryiko 		goto put_token;
2826290248a5SAndrii Nakryiko 	}
282709756af4SAlexei Starovoitov 
28285e43f899SAndrey Ignatov 	prog->expected_attach_type = attr->expected_attach_type;
282966c84731SAndrii Nakryiko 	prog->sleepable = !!(attr->prog_flags & BPF_F_SLEEPABLE);
2830290248a5SAndrii Nakryiko 	prog->aux->attach_btf = attach_btf;
2831ccfe29ebSAlexei Starovoitov 	prog->aux->attach_btf_id = attr->attach_btf_id;
28323aac1eadSToke Høiland-Jørgensen 	prog->aux->dst_prog = dst_prog;
28332b3486bcSStanislav Fomichev 	prog->aux->dev_bound = !!attr->prog_ifindex;
2834c2f2cdbeSLorenzo Bianconi 	prog->aux->xdp_has_frags = attr->prog_flags & BPF_F_XDP_HAS_FRAGS;
28359a18eedbSJakub Kicinski 
2836caf8f28eSAndrii Nakryiko 	/* move token into prog->aux, reuse taken refcnt */
2837caf8f28eSAndrii Nakryiko 	prog->aux->token = token;
2838caf8f28eSAndrii Nakryiko 	token = NULL;
2839caf8f28eSAndrii Nakryiko 
28403ac1f01bSRoman Gushchin 	prog->aux->user = get_current_user();
284109756af4SAlexei Starovoitov 	prog->len = attr->insn_cnt;
284209756af4SAlexei Starovoitov 
284309756af4SAlexei Starovoitov 	err = -EFAULT;
2844af2ac3e1SAlexei Starovoitov 	if (copy_from_bpfptr(prog->insns,
2845af2ac3e1SAlexei Starovoitov 			     make_bpfptr(attr->insns, uattr.is_kernel),
2846aafe6ae9SDaniel Borkmann 			     bpf_prog_insn_size(prog)) != 0)
28471b67772eSAndrii Nakryiko 		goto free_prog;
28487f6719f7SAndrii Nakryiko 	/* copy eBPF program license from user space */
28497f6719f7SAndrii Nakryiko 	if (strncpy_from_bpfptr(license,
28507f6719f7SAndrii Nakryiko 				make_bpfptr(attr->license, uattr.is_kernel),
28517f6719f7SAndrii Nakryiko 				sizeof(license) - 1) < 0)
28521b67772eSAndrii Nakryiko 		goto free_prog;
28537f6719f7SAndrii Nakryiko 	license[sizeof(license) - 1] = 0;
28547f6719f7SAndrii Nakryiko 
28557f6719f7SAndrii Nakryiko 	/* eBPF programs must be GPL compatible to use GPL-ed functions */
28567f6719f7SAndrii Nakryiko 	prog->gpl_compatible = license_is_gpl_compatible(license) ? 1 : 0;
285709756af4SAlexei Starovoitov 
285809756af4SAlexei Starovoitov 	prog->orig_prog = NULL;
2859a91263d5SDaniel Borkmann 	prog->jited = 0;
286009756af4SAlexei Starovoitov 
286185192dbfSAndrii Nakryiko 	atomic64_set(&prog->aux->refcnt, 1);
286209756af4SAlexei Starovoitov 
28639a18eedbSJakub Kicinski 	if (bpf_prog_is_dev_bound(prog->aux)) {
28642b3486bcSStanislav Fomichev 		err = bpf_prog_dev_bound_init(prog, attr);
2865ab3f0063SJakub Kicinski 		if (err)
28661b67772eSAndrii Nakryiko 			goto free_prog;
2867ab3f0063SJakub Kicinski 	}
2868ab3f0063SJakub Kicinski 
2869fd7c211dSToke Høiland-Jørgensen 	if (type == BPF_PROG_TYPE_EXT && dst_prog &&
2870fd7c211dSToke Høiland-Jørgensen 	    bpf_prog_is_dev_bound(dst_prog->aux)) {
2871fd7c211dSToke Høiland-Jørgensen 		err = bpf_prog_dev_bound_inherit(prog, dst_prog);
2872cb4d2b3fSMartin KaFai Lau 		if (err)
28731b67772eSAndrii Nakryiko 			goto free_prog;
2874cb4d2b3fSMartin KaFai Lau 	}
2875cb4d2b3fSMartin KaFai Lau 
287619bfcdf9SDmitrii Dolgov 	/*
287719bfcdf9SDmitrii Dolgov 	 * Bookkeeping for managing the program attachment chain.
287819bfcdf9SDmitrii Dolgov 	 *
287919bfcdf9SDmitrii Dolgov 	 * It might be tempting to set attach_tracing_prog flag at the attachment
288019bfcdf9SDmitrii Dolgov 	 * time, but this will not prevent from loading bunch of tracing prog
288119bfcdf9SDmitrii Dolgov 	 * first, then attach them one to another.
288219bfcdf9SDmitrii Dolgov 	 *
288319bfcdf9SDmitrii Dolgov 	 * The flag attach_tracing_prog is set for the whole program lifecycle, and
288419bfcdf9SDmitrii Dolgov 	 * doesn't have to be cleared in bpf_tracing_link_release, since tracing
288519bfcdf9SDmitrii Dolgov 	 * programs cannot change attachment target.
288619bfcdf9SDmitrii Dolgov 	 */
288719bfcdf9SDmitrii Dolgov 	if (type == BPF_PROG_TYPE_TRACING && dst_prog &&
288819bfcdf9SDmitrii Dolgov 	    dst_prog->type == BPF_PROG_TYPE_TRACING) {
288919bfcdf9SDmitrii Dolgov 		prog->aux->attach_tracing_prog = true;
289019bfcdf9SDmitrii Dolgov 	}
289119bfcdf9SDmitrii Dolgov 
289209756af4SAlexei Starovoitov 	/* find program type: socket_filter vs tracing_filter */
289309756af4SAlexei Starovoitov 	err = find_prog_type(type, prog);
289409756af4SAlexei Starovoitov 	if (err < 0)
28951b67772eSAndrii Nakryiko 		goto free_prog;
289609756af4SAlexei Starovoitov 
28979285ec4cSJason A. Donenfeld 	prog->aux->load_time = ktime_get_boottime_ns();
28988e7ae251SMartin KaFai Lau 	err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name,
28998e7ae251SMartin KaFai Lau 			       sizeof(attr->prog_name));
29008e7ae251SMartin KaFai Lau 	if (err < 0)
29011b67772eSAndrii Nakryiko 		goto free_prog;
29021b67772eSAndrii Nakryiko 
29031b67772eSAndrii Nakryiko 	err = security_bpf_prog_load(prog, attr, token);
29041b67772eSAndrii Nakryiko 	if (err)
29053ac1f01bSRoman Gushchin 		goto free_prog_sec;
2906cb4d2b3fSMartin KaFai Lau 
290709756af4SAlexei Starovoitov 	/* run eBPF verifier */
290847a71c1fSAndrii Nakryiko 	err = bpf_check(&prog, attr, uattr, uattr_size);
290909756af4SAlexei Starovoitov 	if (err < 0)
291009756af4SAlexei Starovoitov 		goto free_used_maps;
291109756af4SAlexei Starovoitov 
2912d1c55ab5SDaniel Borkmann 	prog = bpf_prog_select_runtime(prog, &err);
291304fd61abSAlexei Starovoitov 	if (err < 0)
291404fd61abSAlexei Starovoitov 		goto free_used_maps;
291509756af4SAlexei Starovoitov 
2916dc4bb0e2SMartin KaFai Lau 	err = bpf_prog_alloc_id(prog);
2917dc4bb0e2SMartin KaFai Lau 	if (err)
2918dc4bb0e2SMartin KaFai Lau 		goto free_used_maps;
2919dc4bb0e2SMartin KaFai Lau 
2920c751798aSDaniel Borkmann 	/* Upon success of bpf_prog_alloc_id(), the BPF prog is
2921c751798aSDaniel Borkmann 	 * effectively publicly exposed. However, retrieving via
2922c751798aSDaniel Borkmann 	 * bpf_prog_get_fd_by_id() will take another reference,
2923c751798aSDaniel Borkmann 	 * therefore it cannot be gone underneath us.
2924c751798aSDaniel Borkmann 	 *
2925c751798aSDaniel Borkmann 	 * Only for the time /after/ successful bpf_prog_new_fd()
2926c751798aSDaniel Borkmann 	 * and before returning to userspace, we might just hold
2927c751798aSDaniel Borkmann 	 * one reference and any parallel close on that fd could
2928c751798aSDaniel Borkmann 	 * rip everything out. Hence, below notifications must
2929c751798aSDaniel Borkmann 	 * happen before bpf_prog_new_fd().
2930c751798aSDaniel Borkmann 	 *
2931c751798aSDaniel Borkmann 	 * Also, any failure handling from this point onwards must
2932c751798aSDaniel Borkmann 	 * be using bpf_prog_put() given the program is exposed.
2933b16d9aa4SMartin KaFai Lau 	 */
293474451e66SDaniel Borkmann 	bpf_prog_kallsyms_add(prog);
29356ee52e2aSSong Liu 	perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0);
2936bae141f5SDaniel Borkmann 	bpf_audit_prog(prog, BPF_AUDIT_LOAD);
2937c751798aSDaniel Borkmann 
2938c751798aSDaniel Borkmann 	err = bpf_prog_new_fd(prog);
2939c751798aSDaniel Borkmann 	if (err < 0)
2940c751798aSDaniel Borkmann 		bpf_prog_put(prog);
294109756af4SAlexei Starovoitov 	return err;
294209756af4SAlexei Starovoitov 
294309756af4SAlexei Starovoitov free_used_maps:
2944cd7455f1SDaniel Borkmann 	/* In case we have subprogs, we need to wait for a grace
2945cd7455f1SDaniel Borkmann 	 * period before we can tear down JIT memory since symbols
2946cd7455f1SDaniel Borkmann 	 * are already exposed under kallsyms.
2947cd7455f1SDaniel Borkmann 	 */
2948335d1c5bSKumar Kartikeya Dwivedi 	__bpf_prog_put_noref(prog, prog->aux->real_func_cnt);
2949cd7455f1SDaniel Borkmann 	return err;
29501b67772eSAndrii Nakryiko 
2951afdb09c7SChenbo Feng free_prog_sec:
29521b67772eSAndrii Nakryiko 	security_bpf_prog_free(prog);
2953d17aff80SAndrii Nakryiko free_prog:
29541b67772eSAndrii Nakryiko 	free_uid(prog->aux->user);
295522dc4a0fSAndrii Nakryiko 	if (prog->aux->attach_btf)
295622dc4a0fSAndrii Nakryiko 		btf_put(prog->aux->attach_btf);
295709756af4SAlexei Starovoitov 	bpf_prog_free(prog);
2958caf8f28eSAndrii Nakryiko put_token:
2959caf8f28eSAndrii Nakryiko 	bpf_token_put(token);
296009756af4SAlexei Starovoitov 	return err;
296109756af4SAlexei Starovoitov }
296209756af4SAlexei Starovoitov 
2963cb8edce2SAndrii Nakryiko #define BPF_OBJ_LAST_FIELD path_fd
2964b2197755SDaniel Borkmann 
bpf_obj_pin(const union bpf_attr * attr)2965b2197755SDaniel Borkmann static int bpf_obj_pin(const union bpf_attr *attr)
2966b2197755SDaniel Borkmann {
2967cb8edce2SAndrii Nakryiko 	int path_fd;
2968cb8edce2SAndrii Nakryiko 
2969cb8edce2SAndrii Nakryiko 	if (CHECK_ATTR(BPF_OBJ) || attr->file_flags & ~BPF_F_PATH_FD)
2970b2197755SDaniel Borkmann 		return -EINVAL;
2971b2197755SDaniel Borkmann 
2972cb8edce2SAndrii Nakryiko 	/* path_fd has to be accompanied by BPF_F_PATH_FD flag */
2973cb8edce2SAndrii Nakryiko 	if (!(attr->file_flags & BPF_F_PATH_FD) && attr->path_fd)
2974cb8edce2SAndrii Nakryiko 		return -EINVAL;
2975cb8edce2SAndrii Nakryiko 
2976cb8edce2SAndrii Nakryiko 	path_fd = attr->file_flags & BPF_F_PATH_FD ? attr->path_fd : AT_FDCWD;
2977cb8edce2SAndrii Nakryiko 	return bpf_obj_pin_user(attr->bpf_fd, path_fd,
2978cb8edce2SAndrii Nakryiko 				u64_to_user_ptr(attr->pathname));
2979b2197755SDaniel Borkmann }
2980b2197755SDaniel Borkmann 
bpf_obj_get(const union bpf_attr * attr)2981b2197755SDaniel Borkmann static int bpf_obj_get(const union bpf_attr *attr)
2982b2197755SDaniel Borkmann {
2983cb8edce2SAndrii Nakryiko 	int path_fd;
2984cb8edce2SAndrii Nakryiko 
29856e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 ||
2986cb8edce2SAndrii Nakryiko 	    attr->file_flags & ~(BPF_OBJ_FLAG_MASK | BPF_F_PATH_FD))
2987b2197755SDaniel Borkmann 		return -EINVAL;
2988b2197755SDaniel Borkmann 
2989cb8edce2SAndrii Nakryiko 	/* path_fd has to be accompanied by BPF_F_PATH_FD flag */
2990cb8edce2SAndrii Nakryiko 	if (!(attr->file_flags & BPF_F_PATH_FD) && attr->path_fd)
2991cb8edce2SAndrii Nakryiko 		return -EINVAL;
2992cb8edce2SAndrii Nakryiko 
2993cb8edce2SAndrii Nakryiko 	path_fd = attr->file_flags & BPF_F_PATH_FD ? attr->path_fd : AT_FDCWD;
2994cb8edce2SAndrii Nakryiko 	return bpf_obj_get_user(path_fd, u64_to_user_ptr(attr->pathname),
29956e71b04aSChenbo Feng 				attr->file_flags);
2996b2197755SDaniel Borkmann }
2997b2197755SDaniel Borkmann 
bpf_link_init(struct bpf_link * link,enum bpf_link_type type,const struct bpf_link_ops * ops,struct bpf_prog * prog)2998f2e10bffSAndrii Nakryiko void bpf_link_init(struct bpf_link *link, enum bpf_link_type type,
2999a3b80e10SAndrii Nakryiko 		   const struct bpf_link_ops *ops, struct bpf_prog *prog)
300070ed506cSAndrii Nakryiko {
30012884dc7dSCong Wang 	WARN_ON(ops->dealloc && ops->dealloc_deferred);
300270ed506cSAndrii Nakryiko 	atomic64_set(&link->refcnt, 1);
3003f2e10bffSAndrii Nakryiko 	link->type = type;
3004a3b80e10SAndrii Nakryiko 	link->id = 0;
300570ed506cSAndrii Nakryiko 	link->ops = ops;
300670ed506cSAndrii Nakryiko 	link->prog = prog;
300770ed506cSAndrii Nakryiko }
300870ed506cSAndrii Nakryiko 
bpf_link_free_id(int id)3009a3b80e10SAndrii Nakryiko static void bpf_link_free_id(int id)
3010a3b80e10SAndrii Nakryiko {
3011a3b80e10SAndrii Nakryiko 	if (!id)
3012a3b80e10SAndrii Nakryiko 		return;
3013a3b80e10SAndrii Nakryiko 
3014a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
3015a3b80e10SAndrii Nakryiko 	idr_remove(&link_idr, id);
3016a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
3017a3b80e10SAndrii Nakryiko }
3018a3b80e10SAndrii Nakryiko 
301998868668SAndrii Nakryiko /* Clean up bpf_link and corresponding anon_inode file and FD. After
302098868668SAndrii Nakryiko  * anon_inode is created, bpf_link can't be just kfree()'d due to deferred
3021a3b80e10SAndrii Nakryiko  * anon_inode's release() call. This helper marks bpf_link as
3022a3b80e10SAndrii Nakryiko  * defunct, releases anon_inode file and puts reserved FD. bpf_prog's refcnt
3023a3b80e10SAndrii Nakryiko  * is not decremented, it's the responsibility of a calling code that failed
3024a3b80e10SAndrii Nakryiko  * to complete bpf_link initialization.
302589ae89f5SJiri Olsa  * This helper eventually calls link's dealloc callback, but does not call
302689ae89f5SJiri Olsa  * link's release callback.
302798868668SAndrii Nakryiko  */
bpf_link_cleanup(struct bpf_link_primer * primer)3028a3b80e10SAndrii Nakryiko void bpf_link_cleanup(struct bpf_link_primer *primer)
3029babf3164SAndrii Nakryiko {
3030a3b80e10SAndrii Nakryiko 	primer->link->prog = NULL;
3031a3b80e10SAndrii Nakryiko 	bpf_link_free_id(primer->id);
3032a3b80e10SAndrii Nakryiko 	fput(primer->file);
3033a3b80e10SAndrii Nakryiko 	put_unused_fd(primer->fd);
3034babf3164SAndrii Nakryiko }
3035babf3164SAndrii Nakryiko 
bpf_link_inc(struct bpf_link * link)303670ed506cSAndrii Nakryiko void bpf_link_inc(struct bpf_link *link)
303770ed506cSAndrii Nakryiko {
303870ed506cSAndrii Nakryiko 	atomic64_inc(&link->refcnt);
303970ed506cSAndrii Nakryiko }
304070ed506cSAndrii Nakryiko 
bpf_link_defer_dealloc_rcu_gp(struct rcu_head * rcu)30411a80dbcbSAndrii Nakryiko static void bpf_link_defer_dealloc_rcu_gp(struct rcu_head *rcu)
30421a80dbcbSAndrii Nakryiko {
30431a80dbcbSAndrii Nakryiko 	struct bpf_link *link = container_of(rcu, struct bpf_link, rcu);
30441a80dbcbSAndrii Nakryiko 
30451a80dbcbSAndrii Nakryiko 	/* free bpf_link and its containing memory */
30461a80dbcbSAndrii Nakryiko 	link->ops->dealloc_deferred(link);
30471a80dbcbSAndrii Nakryiko }
30481a80dbcbSAndrii Nakryiko 
bpf_link_defer_dealloc_mult_rcu_gp(struct rcu_head * rcu)30491a80dbcbSAndrii Nakryiko static void bpf_link_defer_dealloc_mult_rcu_gp(struct rcu_head *rcu)
30501a80dbcbSAndrii Nakryiko {
30511a80dbcbSAndrii Nakryiko 	if (rcu_trace_implies_rcu_gp())
30521a80dbcbSAndrii Nakryiko 		bpf_link_defer_dealloc_rcu_gp(rcu);
30531a80dbcbSAndrii Nakryiko 	else
30541a80dbcbSAndrii Nakryiko 		call_rcu(rcu, bpf_link_defer_dealloc_rcu_gp);
30551a80dbcbSAndrii Nakryiko }
30561a80dbcbSAndrii Nakryiko 
305770ed506cSAndrii Nakryiko /* bpf_link_free is guaranteed to be called from process context */
bpf_link_free(struct bpf_link * link)305870ed506cSAndrii Nakryiko static void bpf_link_free(struct bpf_link *link)
305970ed506cSAndrii Nakryiko {
30602884dc7dSCong Wang 	const struct bpf_link_ops *ops = link->ops;
30611a80dbcbSAndrii Nakryiko 	bool sleepable = false;
30621a80dbcbSAndrii Nakryiko 
3063a3b80e10SAndrii Nakryiko 	bpf_link_free_id(link->id);
3064babf3164SAndrii Nakryiko 	if (link->prog) {
30651a80dbcbSAndrii Nakryiko 		sleepable = link->prog->sleepable;
3066babf3164SAndrii Nakryiko 		/* detach BPF program, clean up used resources */
30672884dc7dSCong Wang 		ops->release(link);
3068babf3164SAndrii Nakryiko 		bpf_prog_put(link->prog);
3069babf3164SAndrii Nakryiko 	}
30702884dc7dSCong Wang 	if (ops->dealloc_deferred) {
30711a80dbcbSAndrii Nakryiko 		/* schedule BPF link deallocation; if underlying BPF program
30721a80dbcbSAndrii Nakryiko 		 * is sleepable, we need to first wait for RCU tasks trace
30731a80dbcbSAndrii Nakryiko 		 * sync, then go through "classic" RCU grace period
30741a80dbcbSAndrii Nakryiko 		 */
30751a80dbcbSAndrii Nakryiko 		if (sleepable)
30761a80dbcbSAndrii Nakryiko 			call_rcu_tasks_trace(&link->rcu, bpf_link_defer_dealloc_mult_rcu_gp);
30771a80dbcbSAndrii Nakryiko 		else
30781a80dbcbSAndrii Nakryiko 			call_rcu(&link->rcu, bpf_link_defer_dealloc_rcu_gp);
30792884dc7dSCong Wang 	} else if (ops->dealloc)
30802884dc7dSCong Wang 		ops->dealloc(link);
308170ed506cSAndrii Nakryiko }
308270ed506cSAndrii Nakryiko 
bpf_link_put_deferred(struct work_struct * work)308370ed506cSAndrii Nakryiko static void bpf_link_put_deferred(struct work_struct *work)
308470ed506cSAndrii Nakryiko {
308570ed506cSAndrii Nakryiko 	struct bpf_link *link = container_of(work, struct bpf_link, work);
308670ed506cSAndrii Nakryiko 
308770ed506cSAndrii Nakryiko 	bpf_link_free(link);
308870ed506cSAndrii Nakryiko }
308970ed506cSAndrii Nakryiko 
3090ab5d47bdSSebastian Andrzej Siewior /* bpf_link_put might be called from atomic context. It needs to be called
3091ab5d47bdSSebastian Andrzej Siewior  * from sleepable context in order to acquire sleeping locks during the process.
309270ed506cSAndrii Nakryiko  */
bpf_link_put(struct bpf_link * link)309370ed506cSAndrii Nakryiko void bpf_link_put(struct bpf_link *link)
309470ed506cSAndrii Nakryiko {
309570ed506cSAndrii Nakryiko 	if (!atomic64_dec_and_test(&link->refcnt))
309670ed506cSAndrii Nakryiko 		return;
309770ed506cSAndrii Nakryiko 
309870ed506cSAndrii Nakryiko 	INIT_WORK(&link->work, bpf_link_put_deferred);
309970ed506cSAndrii Nakryiko 	schedule_work(&link->work);
310070ed506cSAndrii Nakryiko }
3101cb80ddc6SAlexei Starovoitov EXPORT_SYMBOL(bpf_link_put);
310270ed506cSAndrii Nakryiko 
bpf_link_put_direct(struct bpf_link * link)3103ab5d47bdSSebastian Andrzej Siewior static void bpf_link_put_direct(struct bpf_link *link)
3104ab5d47bdSSebastian Andrzej Siewior {
3105ab5d47bdSSebastian Andrzej Siewior 	if (!atomic64_dec_and_test(&link->refcnt))
3106ab5d47bdSSebastian Andrzej Siewior 		return;
3107ab5d47bdSSebastian Andrzej Siewior 	bpf_link_free(link);
3108ab5d47bdSSebastian Andrzej Siewior }
3109ab5d47bdSSebastian Andrzej Siewior 
bpf_link_release(struct inode * inode,struct file * filp)311070ed506cSAndrii Nakryiko static int bpf_link_release(struct inode *inode, struct file *filp)
311170ed506cSAndrii Nakryiko {
311270ed506cSAndrii Nakryiko 	struct bpf_link *link = filp->private_data;
311370ed506cSAndrii Nakryiko 
3114ab5d47bdSSebastian Andrzej Siewior 	bpf_link_put_direct(link);
3115fec56f58SAlexei Starovoitov 	return 0;
3116fec56f58SAlexei Starovoitov }
3117fec56f58SAlexei Starovoitov 
311870ed506cSAndrii Nakryiko #ifdef CONFIG_PROC_FS
3119f2e10bffSAndrii Nakryiko #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type)
3120f2e10bffSAndrii Nakryiko #define BPF_MAP_TYPE(_id, _ops)
3121f2e10bffSAndrii Nakryiko #define BPF_LINK_TYPE(_id, _name) [_id] = #_name,
3122f2e10bffSAndrii Nakryiko static const char *bpf_link_type_strs[] = {
3123f2e10bffSAndrii Nakryiko 	[BPF_LINK_TYPE_UNSPEC] = "<invalid>",
3124f2e10bffSAndrii Nakryiko #include <linux/bpf_types.h>
3125f2e10bffSAndrii Nakryiko };
3126f2e10bffSAndrii Nakryiko #undef BPF_PROG_TYPE
3127f2e10bffSAndrii Nakryiko #undef BPF_MAP_TYPE
3128f2e10bffSAndrii Nakryiko #undef BPF_LINK_TYPE
312970ed506cSAndrii Nakryiko 
bpf_link_show_fdinfo(struct seq_file * m,struct file * filp)313070ed506cSAndrii Nakryiko static void bpf_link_show_fdinfo(struct seq_file *m, struct file *filp)
313170ed506cSAndrii Nakryiko {
313270ed506cSAndrii Nakryiko 	const struct bpf_link *link = filp->private_data;
313370ed506cSAndrii Nakryiko 	const struct bpf_prog *prog = link->prog;
313470ed506cSAndrii Nakryiko 	char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
313570ed506cSAndrii Nakryiko 
313670ed506cSAndrii Nakryiko 	seq_printf(m,
313770ed506cSAndrii Nakryiko 		   "link_type:\t%s\n"
313868b04864SKui-Feng Lee 		   "link_id:\t%u\n",
313968b04864SKui-Feng Lee 		   bpf_link_type_strs[link->type],
314068b04864SKui-Feng Lee 		   link->id);
314168b04864SKui-Feng Lee 	if (prog) {
314268b04864SKui-Feng Lee 		bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
314368b04864SKui-Feng Lee 		seq_printf(m,
314470ed506cSAndrii Nakryiko 			   "prog_tag:\t%s\n"
314570ed506cSAndrii Nakryiko 			   "prog_id:\t%u\n",
314670ed506cSAndrii Nakryiko 			   prog_tag,
314770ed506cSAndrii Nakryiko 			   prog->aux->id);
314868b04864SKui-Feng Lee 	}
3149f2e10bffSAndrii Nakryiko 	if (link->ops->show_fdinfo)
3150f2e10bffSAndrii Nakryiko 		link->ops->show_fdinfo(link, m);
315170ed506cSAndrii Nakryiko }
315270ed506cSAndrii Nakryiko #endif
315370ed506cSAndrii Nakryiko 
bpf_link_poll(struct file * file,struct poll_table_struct * pts)31541adddc97SKui-Feng Lee static __poll_t bpf_link_poll(struct file *file, struct poll_table_struct *pts)
31551adddc97SKui-Feng Lee {
31561adddc97SKui-Feng Lee 	struct bpf_link *link = file->private_data;
31571adddc97SKui-Feng Lee 
31581adddc97SKui-Feng Lee 	return link->ops->poll(file, pts);
31591adddc97SKui-Feng Lee }
31601adddc97SKui-Feng Lee 
31616f302bfbSZou Wei static const struct file_operations bpf_link_fops = {
316270ed506cSAndrii Nakryiko #ifdef CONFIG_PROC_FS
316370ed506cSAndrii Nakryiko 	.show_fdinfo	= bpf_link_show_fdinfo,
316470ed506cSAndrii Nakryiko #endif
316570ed506cSAndrii Nakryiko 	.release	= bpf_link_release,
3166fec56f58SAlexei Starovoitov 	.read		= bpf_dummy_read,
3167fec56f58SAlexei Starovoitov 	.write		= bpf_dummy_write,
3168fec56f58SAlexei Starovoitov };
3169fec56f58SAlexei Starovoitov 
31701adddc97SKui-Feng Lee static const struct file_operations bpf_link_fops_poll = {
31711adddc97SKui-Feng Lee #ifdef CONFIG_PROC_FS
31721adddc97SKui-Feng Lee 	.show_fdinfo	= bpf_link_show_fdinfo,
31731adddc97SKui-Feng Lee #endif
31741adddc97SKui-Feng Lee 	.release	= bpf_link_release,
31751adddc97SKui-Feng Lee 	.read		= bpf_dummy_read,
31761adddc97SKui-Feng Lee 	.write		= bpf_dummy_write,
31771adddc97SKui-Feng Lee 	.poll		= bpf_link_poll,
31781adddc97SKui-Feng Lee };
31791adddc97SKui-Feng Lee 
bpf_link_alloc_id(struct bpf_link * link)3180a3b80e10SAndrii Nakryiko static int bpf_link_alloc_id(struct bpf_link *link)
318170ed506cSAndrii Nakryiko {
3182a3b80e10SAndrii Nakryiko 	int id;
3183a3b80e10SAndrii Nakryiko 
3184a3b80e10SAndrii Nakryiko 	idr_preload(GFP_KERNEL);
3185a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
3186a3b80e10SAndrii Nakryiko 	id = idr_alloc_cyclic(&link_idr, link, 1, INT_MAX, GFP_ATOMIC);
3187a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
3188a3b80e10SAndrii Nakryiko 	idr_preload_end();
3189a3b80e10SAndrii Nakryiko 
3190a3b80e10SAndrii Nakryiko 	return id;
319170ed506cSAndrii Nakryiko }
319270ed506cSAndrii Nakryiko 
3193a3b80e10SAndrii Nakryiko /* Prepare bpf_link to be exposed to user-space by allocating anon_inode file,
3194a3b80e10SAndrii Nakryiko  * reserving unused FD and allocating ID from link_idr. This is to be paired
3195a3b80e10SAndrii Nakryiko  * with bpf_link_settle() to install FD and ID and expose bpf_link to
3196a3b80e10SAndrii Nakryiko  * user-space, if bpf_link is successfully attached. If not, bpf_link and
3197a3b80e10SAndrii Nakryiko  * pre-allocated resources are to be freed with bpf_cleanup() call. All the
3198a3b80e10SAndrii Nakryiko  * transient state is passed around in struct bpf_link_primer.
3199a3b80e10SAndrii Nakryiko  * This is preferred way to create and initialize bpf_link, especially when
3200a3b80e10SAndrii Nakryiko  * there are complicated and expensive operations in between creating bpf_link
3201a3b80e10SAndrii Nakryiko  * itself and attaching it to BPF hook. By using bpf_link_prime() and
3202a3b80e10SAndrii Nakryiko  * bpf_link_settle() kernel code using bpf_link doesn't have to perform
3203a3b80e10SAndrii Nakryiko  * expensive (and potentially failing) roll back operations in a rare case
3204a3b80e10SAndrii Nakryiko  * that file, FD, or ID can't be allocated.
3205babf3164SAndrii Nakryiko  */
bpf_link_prime(struct bpf_link * link,struct bpf_link_primer * primer)3206a3b80e10SAndrii Nakryiko int bpf_link_prime(struct bpf_link *link, struct bpf_link_primer *primer)
3207babf3164SAndrii Nakryiko {
3208babf3164SAndrii Nakryiko 	struct file *file;
3209a3b80e10SAndrii Nakryiko 	int fd, id;
3210babf3164SAndrii Nakryiko 
3211babf3164SAndrii Nakryiko 	fd = get_unused_fd_flags(O_CLOEXEC);
3212babf3164SAndrii Nakryiko 	if (fd < 0)
3213a3b80e10SAndrii Nakryiko 		return fd;
3214babf3164SAndrii Nakryiko 
3215babf3164SAndrii Nakryiko 
3216a3b80e10SAndrii Nakryiko 	id = bpf_link_alloc_id(link);
3217a3b80e10SAndrii Nakryiko 	if (id < 0) {
3218a3b80e10SAndrii Nakryiko 		put_unused_fd(fd);
3219a3b80e10SAndrii Nakryiko 		return id;
3220a3b80e10SAndrii Nakryiko 	}
3221babf3164SAndrii Nakryiko 
32221adddc97SKui-Feng Lee 	file = anon_inode_getfile("bpf_link",
32231adddc97SKui-Feng Lee 				  link->ops->poll ? &bpf_link_fops_poll : &bpf_link_fops,
32241adddc97SKui-Feng Lee 				  link, O_CLOEXEC);
3225babf3164SAndrii Nakryiko 	if (IS_ERR(file)) {
3226138c6767SAndrii Nakryiko 		bpf_link_free_id(id);
3227babf3164SAndrii Nakryiko 		put_unused_fd(fd);
3228138c6767SAndrii Nakryiko 		return PTR_ERR(file);
3229babf3164SAndrii Nakryiko 	}
3230babf3164SAndrii Nakryiko 
3231a3b80e10SAndrii Nakryiko 	primer->link = link;
3232a3b80e10SAndrii Nakryiko 	primer->file = file;
3233a3b80e10SAndrii Nakryiko 	primer->fd = fd;
3234a3b80e10SAndrii Nakryiko 	primer->id = id;
3235a3b80e10SAndrii Nakryiko 	return 0;
3236a3b80e10SAndrii Nakryiko }
3237a3b80e10SAndrii Nakryiko 
bpf_link_settle(struct bpf_link_primer * primer)3238a3b80e10SAndrii Nakryiko int bpf_link_settle(struct bpf_link_primer *primer)
3239a3b80e10SAndrii Nakryiko {
3240a3b80e10SAndrii Nakryiko 	/* make bpf_link fetchable by ID */
3241a3b80e10SAndrii Nakryiko 	spin_lock_bh(&link_idr_lock);
3242a3b80e10SAndrii Nakryiko 	primer->link->id = primer->id;
3243a3b80e10SAndrii Nakryiko 	spin_unlock_bh(&link_idr_lock);
3244a3b80e10SAndrii Nakryiko 	/* make bpf_link fetchable by FD */
3245a3b80e10SAndrii Nakryiko 	fd_install(primer->fd, primer->file);
3246a3b80e10SAndrii Nakryiko 	/* pass through installed FD */
3247a3b80e10SAndrii Nakryiko 	return primer->fd;
3248a3b80e10SAndrii Nakryiko }
3249a3b80e10SAndrii Nakryiko 
bpf_link_new_fd(struct bpf_link * link)3250a3b80e10SAndrii Nakryiko int bpf_link_new_fd(struct bpf_link *link)
3251a3b80e10SAndrii Nakryiko {
32521adddc97SKui-Feng Lee 	return anon_inode_getfd("bpf-link",
32531adddc97SKui-Feng Lee 				link->ops->poll ? &bpf_link_fops_poll : &bpf_link_fops,
32541adddc97SKui-Feng Lee 				link, O_CLOEXEC);
3255babf3164SAndrii Nakryiko }
3256babf3164SAndrii Nakryiko 
bpf_link_get_from_fd(u32 ufd)325770ed506cSAndrii Nakryiko struct bpf_link *bpf_link_get_from_fd(u32 ufd)
325870ed506cSAndrii Nakryiko {
325970ed506cSAndrii Nakryiko 	struct fd f = fdget(ufd);
326070ed506cSAndrii Nakryiko 	struct bpf_link *link;
326170ed506cSAndrii Nakryiko 
326270ed506cSAndrii Nakryiko 	if (!f.file)
326370ed506cSAndrii Nakryiko 		return ERR_PTR(-EBADF);
32641adddc97SKui-Feng Lee 	if (f.file->f_op != &bpf_link_fops && f.file->f_op != &bpf_link_fops_poll) {
326570ed506cSAndrii Nakryiko 		fdput(f);
326670ed506cSAndrii Nakryiko 		return ERR_PTR(-EINVAL);
326770ed506cSAndrii Nakryiko 	}
326870ed506cSAndrii Nakryiko 
326970ed506cSAndrii Nakryiko 	link = f.file->private_data;
327070ed506cSAndrii Nakryiko 	bpf_link_inc(link);
327170ed506cSAndrii Nakryiko 	fdput(f);
327270ed506cSAndrii Nakryiko 
327370ed506cSAndrii Nakryiko 	return link;
327470ed506cSAndrii Nakryiko }
3275cb80ddc6SAlexei Starovoitov EXPORT_SYMBOL(bpf_link_get_from_fd);
327670ed506cSAndrii Nakryiko 
bpf_tracing_link_release(struct bpf_link * link)327770ed506cSAndrii Nakryiko static void bpf_tracing_link_release(struct bpf_link *link)
327870ed506cSAndrii Nakryiko {
32793aac1eadSToke Høiland-Jørgensen 	struct bpf_tracing_link *tr_link =
3280f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
32813aac1eadSToke Høiland-Jørgensen 
3282f7e0beafSKui-Feng Lee 	WARN_ON_ONCE(bpf_trampoline_unlink_prog(&tr_link->link,
32833aac1eadSToke Høiland-Jørgensen 						tr_link->trampoline));
32843aac1eadSToke Høiland-Jørgensen 
32853aac1eadSToke Høiland-Jørgensen 	bpf_trampoline_put(tr_link->trampoline);
32863aac1eadSToke Høiland-Jørgensen 
32873aac1eadSToke Høiland-Jørgensen 	/* tgt_prog is NULL if target is a kernel function */
32883aac1eadSToke Høiland-Jørgensen 	if (tr_link->tgt_prog)
32893aac1eadSToke Høiland-Jørgensen 		bpf_prog_put(tr_link->tgt_prog);
3290babf3164SAndrii Nakryiko }
3291babf3164SAndrii Nakryiko 
bpf_tracing_link_dealloc(struct bpf_link * link)3292babf3164SAndrii Nakryiko static void bpf_tracing_link_dealloc(struct bpf_link *link)
3293babf3164SAndrii Nakryiko {
329470ed506cSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
3295f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
329670ed506cSAndrii Nakryiko 
329770ed506cSAndrii Nakryiko 	kfree(tr_link);
329870ed506cSAndrii Nakryiko }
329970ed506cSAndrii Nakryiko 
bpf_tracing_link_show_fdinfo(const struct bpf_link * link,struct seq_file * seq)3300f2e10bffSAndrii Nakryiko static void bpf_tracing_link_show_fdinfo(const struct bpf_link *link,
3301f2e10bffSAndrii Nakryiko 					 struct seq_file *seq)
3302f2e10bffSAndrii Nakryiko {
3303f2e10bffSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
3304f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
3305e859e429SYafang Shao 	u32 target_btf_id, target_obj_id;
3306f2e10bffSAndrii Nakryiko 
3307e859e429SYafang Shao 	bpf_trampoline_unpack_key(tr_link->trampoline->key,
3308e859e429SYafang Shao 				  &target_obj_id, &target_btf_id);
3309f2e10bffSAndrii Nakryiko 	seq_printf(seq,
3310e859e429SYafang Shao 		   "attach_type:\t%d\n"
3311e859e429SYafang Shao 		   "target_obj_id:\t%u\n"
3312e859e429SYafang Shao 		   "target_btf_id:\t%u\n",
3313e859e429SYafang Shao 		   tr_link->attach_type,
3314e859e429SYafang Shao 		   target_obj_id,
3315e859e429SYafang Shao 		   target_btf_id);
3316f2e10bffSAndrii Nakryiko }
3317f2e10bffSAndrii Nakryiko 
bpf_tracing_link_fill_link_info(const struct bpf_link * link,struct bpf_link_info * info)3318f2e10bffSAndrii Nakryiko static int bpf_tracing_link_fill_link_info(const struct bpf_link *link,
3319f2e10bffSAndrii Nakryiko 					   struct bpf_link_info *info)
3320f2e10bffSAndrii Nakryiko {
3321f2e10bffSAndrii Nakryiko 	struct bpf_tracing_link *tr_link =
3322f7e0beafSKui-Feng Lee 		container_of(link, struct bpf_tracing_link, link.link);
3323f2e10bffSAndrii Nakryiko 
3324f2e10bffSAndrii Nakryiko 	info->tracing.attach_type = tr_link->attach_type;
3325441e8c66SToke Høiland-Jørgensen 	bpf_trampoline_unpack_key(tr_link->trampoline->key,
3326441e8c66SToke Høiland-Jørgensen 				  &info->tracing.target_obj_id,
3327441e8c66SToke Høiland-Jørgensen 				  &info->tracing.target_btf_id);
3328f2e10bffSAndrii Nakryiko 
3329f2e10bffSAndrii Nakryiko 	return 0;
3330f2e10bffSAndrii Nakryiko }
3331f2e10bffSAndrii Nakryiko 
333270ed506cSAndrii Nakryiko static const struct bpf_link_ops bpf_tracing_link_lops = {
333370ed506cSAndrii Nakryiko 	.release = bpf_tracing_link_release,
3334babf3164SAndrii Nakryiko 	.dealloc = bpf_tracing_link_dealloc,
3335f2e10bffSAndrii Nakryiko 	.show_fdinfo = bpf_tracing_link_show_fdinfo,
3336f2e10bffSAndrii Nakryiko 	.fill_link_info = bpf_tracing_link_fill_link_info,
333770ed506cSAndrii Nakryiko };
333870ed506cSAndrii Nakryiko 
bpf_tracing_prog_attach(struct bpf_prog * prog,int tgt_prog_fd,u32 btf_id,u64 bpf_cookie)33394a1e7c0cSToke Høiland-Jørgensen static int bpf_tracing_prog_attach(struct bpf_prog *prog,
33404a1e7c0cSToke Høiland-Jørgensen 				   int tgt_prog_fd,
33412fcc8241SKui-Feng Lee 				   u32 btf_id,
33422fcc8241SKui-Feng Lee 				   u64 bpf_cookie)
3343fec56f58SAlexei Starovoitov {
3344a3b80e10SAndrii Nakryiko 	struct bpf_link_primer link_primer;
33453aac1eadSToke Høiland-Jørgensen 	struct bpf_prog *tgt_prog = NULL;
33464a1e7c0cSToke Høiland-Jørgensen 	struct bpf_trampoline *tr = NULL;
334770ed506cSAndrii Nakryiko 	struct bpf_tracing_link *link;
33484a1e7c0cSToke Høiland-Jørgensen 	u64 key = 0;
3349a3b80e10SAndrii Nakryiko 	int err;
3350fec56f58SAlexei Starovoitov 
33519e4e01dfSKP Singh 	switch (prog->type) {
33529e4e01dfSKP Singh 	case BPF_PROG_TYPE_TRACING:
3353fec56f58SAlexei Starovoitov 		if (prog->expected_attach_type != BPF_TRACE_FENTRY &&
3354be8704ffSAlexei Starovoitov 		    prog->expected_attach_type != BPF_TRACE_FEXIT &&
33559e4e01dfSKP Singh 		    prog->expected_attach_type != BPF_MODIFY_RETURN) {
33569e4e01dfSKP Singh 			err = -EINVAL;
33579e4e01dfSKP Singh 			goto out_put_prog;
33589e4e01dfSKP Singh 		}
33599e4e01dfSKP Singh 		break;
33609e4e01dfSKP Singh 	case BPF_PROG_TYPE_EXT:
33619e4e01dfSKP Singh 		if (prog->expected_attach_type != 0) {
33629e4e01dfSKP Singh 			err = -EINVAL;
33639e4e01dfSKP Singh 			goto out_put_prog;
33649e4e01dfSKP Singh 		}
33659e4e01dfSKP Singh 		break;
33669e4e01dfSKP Singh 	case BPF_PROG_TYPE_LSM:
33679e4e01dfSKP Singh 		if (prog->expected_attach_type != BPF_LSM_MAC) {
33689e4e01dfSKP Singh 			err = -EINVAL;
33699e4e01dfSKP Singh 			goto out_put_prog;
33709e4e01dfSKP Singh 		}
33719e4e01dfSKP Singh 		break;
33729e4e01dfSKP Singh 	default:
3373fec56f58SAlexei Starovoitov 		err = -EINVAL;
3374fec56f58SAlexei Starovoitov 		goto out_put_prog;
3375fec56f58SAlexei Starovoitov 	}
3376fec56f58SAlexei Starovoitov 
33774a1e7c0cSToke Høiland-Jørgensen 	if (!!tgt_prog_fd != !!btf_id) {
33784a1e7c0cSToke Høiland-Jørgensen 		err = -EINVAL;
33794a1e7c0cSToke Høiland-Jørgensen 		goto out_put_prog;
33804a1e7c0cSToke Høiland-Jørgensen 	}
33814a1e7c0cSToke Høiland-Jørgensen 
33824a1e7c0cSToke Høiland-Jørgensen 	if (tgt_prog_fd) {
338319bfcdf9SDmitrii Dolgov 		/*
338419bfcdf9SDmitrii Dolgov 		 * For now we only allow new targets for BPF_PROG_TYPE_EXT. If this
338519bfcdf9SDmitrii Dolgov 		 * part would be changed to implement the same for
338619bfcdf9SDmitrii Dolgov 		 * BPF_PROG_TYPE_TRACING, do not forget to update the way how
338719bfcdf9SDmitrii Dolgov 		 * attach_tracing_prog flag is set.
338819bfcdf9SDmitrii Dolgov 		 */
33894a1e7c0cSToke Høiland-Jørgensen 		if (prog->type != BPF_PROG_TYPE_EXT) {
33904a1e7c0cSToke Høiland-Jørgensen 			err = -EINVAL;
33914a1e7c0cSToke Høiland-Jørgensen 			goto out_put_prog;
33924a1e7c0cSToke Høiland-Jørgensen 		}
33934a1e7c0cSToke Høiland-Jørgensen 
33944a1e7c0cSToke Høiland-Jørgensen 		tgt_prog = bpf_prog_get(tgt_prog_fd);
33954a1e7c0cSToke Høiland-Jørgensen 		if (IS_ERR(tgt_prog)) {
33964a1e7c0cSToke Høiland-Jørgensen 			err = PTR_ERR(tgt_prog);
33974a1e7c0cSToke Høiland-Jørgensen 			tgt_prog = NULL;
33984a1e7c0cSToke Høiland-Jørgensen 			goto out_put_prog;
33994a1e7c0cSToke Høiland-Jørgensen 		}
34004a1e7c0cSToke Høiland-Jørgensen 
340122dc4a0fSAndrii Nakryiko 		key = bpf_trampoline_compute_key(tgt_prog, NULL, btf_id);
34024a1e7c0cSToke Høiland-Jørgensen 	}
34034a1e7c0cSToke Høiland-Jørgensen 
340470ed506cSAndrii Nakryiko 	link = kzalloc(sizeof(*link), GFP_USER);
340570ed506cSAndrii Nakryiko 	if (!link) {
340670ed506cSAndrii Nakryiko 		err = -ENOMEM;
3407fec56f58SAlexei Starovoitov 		goto out_put_prog;
3408fec56f58SAlexei Starovoitov 	}
3409f7e0beafSKui-Feng Lee 	bpf_link_init(&link->link.link, BPF_LINK_TYPE_TRACING,
3410f2e10bffSAndrii Nakryiko 		      &bpf_tracing_link_lops, prog);
3411f2e10bffSAndrii Nakryiko 	link->attach_type = prog->expected_attach_type;
34122fcc8241SKui-Feng Lee 	link->link.cookie = bpf_cookie;
3413fec56f58SAlexei Starovoitov 
34143aac1eadSToke Høiland-Jørgensen 	mutex_lock(&prog->aux->dst_mutex);
3415babf3164SAndrii Nakryiko 
34164a1e7c0cSToke Høiland-Jørgensen 	/* There are a few possible cases here:
34174a1e7c0cSToke Høiland-Jørgensen 	 *
34184a1e7c0cSToke Høiland-Jørgensen 	 * - if prog->aux->dst_trampoline is set, the program was just loaded
34194a1e7c0cSToke Høiland-Jørgensen 	 *   and not yet attached to anything, so we can use the values stored
34204a1e7c0cSToke Høiland-Jørgensen 	 *   in prog->aux
34214a1e7c0cSToke Høiland-Jørgensen 	 *
34224a1e7c0cSToke Høiland-Jørgensen 	 * - if prog->aux->dst_trampoline is NULL, the program has already been
34234a1e7c0cSToke Høiland-Jørgensen          *   attached to a target and its initial target was cleared (below)
34244a1e7c0cSToke Høiland-Jørgensen 	 *
34254a1e7c0cSToke Høiland-Jørgensen 	 * - if tgt_prog != NULL, the caller specified tgt_prog_fd +
34264a1e7c0cSToke Høiland-Jørgensen 	 *   target_btf_id using the link_create API.
34274a1e7c0cSToke Høiland-Jørgensen 	 *
34284a1e7c0cSToke Høiland-Jørgensen 	 * - if tgt_prog == NULL when this function was called using the old
34294a1e7c0cSToke Høiland-Jørgensen 	 *   raw_tracepoint_open API, and we need a target from prog->aux
34304a1e7c0cSToke Høiland-Jørgensen 	 *
3431f3a95075SJiri Olsa 	 * - if prog->aux->dst_trampoline and tgt_prog is NULL, the program
3432f3a95075SJiri Olsa 	 *   was detached and is going for re-attachment.
3433715d82baSJiri Olsa 	 *
3434715d82baSJiri Olsa 	 * - if prog->aux->dst_trampoline is NULL and tgt_prog and prog->aux->attach_btf
3435715d82baSJiri Olsa 	 *   are NULL, then program was already attached and user did not provide
3436715d82baSJiri Olsa 	 *   tgt_prog_fd so we have no way to find out or create trampoline
34374a1e7c0cSToke Høiland-Jørgensen 	 */
34384a1e7c0cSToke Høiland-Jørgensen 	if (!prog->aux->dst_trampoline && !tgt_prog) {
3439f3a95075SJiri Olsa 		/*
3440f3a95075SJiri Olsa 		 * Allow re-attach for TRACING and LSM programs. If it's
3441f3a95075SJiri Olsa 		 * currently linked, bpf_trampoline_link_prog will fail.
3442f3a95075SJiri Olsa 		 * EXT programs need to specify tgt_prog_fd, so they
3443f3a95075SJiri Olsa 		 * re-attach in separate code path.
3444f3a95075SJiri Olsa 		 */
3445f3a95075SJiri Olsa 		if (prog->type != BPF_PROG_TYPE_TRACING &&
3446f3a95075SJiri Olsa 		    prog->type != BPF_PROG_TYPE_LSM) {
3447f3a95075SJiri Olsa 			err = -EINVAL;
34483aac1eadSToke Høiland-Jørgensen 			goto out_unlock;
34493aac1eadSToke Høiland-Jørgensen 		}
3450715d82baSJiri Olsa 		/* We can allow re-attach only if we have valid attach_btf. */
3451715d82baSJiri Olsa 		if (!prog->aux->attach_btf) {
3452715d82baSJiri Olsa 			err = -EINVAL;
3453715d82baSJiri Olsa 			goto out_unlock;
3454715d82baSJiri Olsa 		}
3455f3a95075SJiri Olsa 		btf_id = prog->aux->attach_btf_id;
3456f3a95075SJiri Olsa 		key = bpf_trampoline_compute_key(NULL, prog->aux->attach_btf, btf_id);
3457f3a95075SJiri Olsa 	}
34584a1e7c0cSToke Høiland-Jørgensen 
34594a1e7c0cSToke Høiland-Jørgensen 	if (!prog->aux->dst_trampoline ||
34604a1e7c0cSToke Høiland-Jørgensen 	    (key && key != prog->aux->dst_trampoline->key)) {
34614a1e7c0cSToke Høiland-Jørgensen 		/* If there is no saved target, or the specified target is
34624a1e7c0cSToke Høiland-Jørgensen 		 * different from the destination specified at load time, we
34634a1e7c0cSToke Høiland-Jørgensen 		 * need a new trampoline and a check for compatibility
34644a1e7c0cSToke Høiland-Jørgensen 		 */
34654a1e7c0cSToke Høiland-Jørgensen 		struct bpf_attach_target_info tgt_info = {};
34664a1e7c0cSToke Høiland-Jørgensen 
34674a1e7c0cSToke Høiland-Jørgensen 		err = bpf_check_attach_target(NULL, prog, tgt_prog, btf_id,
34684a1e7c0cSToke Høiland-Jørgensen 					      &tgt_info);
34694a1e7c0cSToke Høiland-Jørgensen 		if (err)
34704a1e7c0cSToke Høiland-Jørgensen 			goto out_unlock;
34714a1e7c0cSToke Høiland-Jørgensen 
347231bf1dbcSViktor Malik 		if (tgt_info.tgt_mod) {
347331bf1dbcSViktor Malik 			module_put(prog->aux->mod);
347431bf1dbcSViktor Malik 			prog->aux->mod = tgt_info.tgt_mod;
347531bf1dbcSViktor Malik 		}
347631bf1dbcSViktor Malik 
34774a1e7c0cSToke Høiland-Jørgensen 		tr = bpf_trampoline_get(key, &tgt_info);
34784a1e7c0cSToke Høiland-Jørgensen 		if (!tr) {
34794a1e7c0cSToke Høiland-Jørgensen 			err = -ENOMEM;
34804a1e7c0cSToke Høiland-Jørgensen 			goto out_unlock;
34814a1e7c0cSToke Høiland-Jørgensen 		}
34824a1e7c0cSToke Høiland-Jørgensen 	} else {
34834a1e7c0cSToke Høiland-Jørgensen 		/* The caller didn't specify a target, or the target was the
34844a1e7c0cSToke Høiland-Jørgensen 		 * same as the destination supplied during program load. This
34854a1e7c0cSToke Høiland-Jørgensen 		 * means we can reuse the trampoline and reference from program
34864a1e7c0cSToke Høiland-Jørgensen 		 * load time, and there is no need to allocate a new one. This
34874a1e7c0cSToke Høiland-Jørgensen 		 * can only happen once for any program, as the saved values in
34884a1e7c0cSToke Høiland-Jørgensen 		 * prog->aux are cleared below.
34894a1e7c0cSToke Høiland-Jørgensen 		 */
34903aac1eadSToke Høiland-Jørgensen 		tr = prog->aux->dst_trampoline;
34913aac1eadSToke Høiland-Jørgensen 		tgt_prog = prog->aux->dst_prog;
34924a1e7c0cSToke Høiland-Jørgensen 	}
34933aac1eadSToke Høiland-Jørgensen 
3494f7e0beafSKui-Feng Lee 	err = bpf_link_prime(&link->link.link, &link_primer);
34953aac1eadSToke Høiland-Jørgensen 	if (err)
34963aac1eadSToke Høiland-Jørgensen 		goto out_unlock;
34973aac1eadSToke Høiland-Jørgensen 
3498f7e0beafSKui-Feng Lee 	err = bpf_trampoline_link_prog(&link->link, tr);
3499babf3164SAndrii Nakryiko 	if (err) {
3500a3b80e10SAndrii Nakryiko 		bpf_link_cleanup(&link_primer);
35013aac1eadSToke Høiland-Jørgensen 		link = NULL;
35023aac1eadSToke Høiland-Jørgensen 		goto out_unlock;
3503babf3164SAndrii Nakryiko 	}
3504babf3164SAndrii Nakryiko 
35053aac1eadSToke Høiland-Jørgensen 	link->tgt_prog = tgt_prog;
35063aac1eadSToke Høiland-Jørgensen 	link->trampoline = tr;
35073aac1eadSToke Høiland-Jørgensen 
35084a1e7c0cSToke Høiland-Jørgensen 	/* Always clear the trampoline and target prog from prog->aux to make
35094a1e7c0cSToke Høiland-Jørgensen 	 * sure the original attach destination is not kept alive after a
35104a1e7c0cSToke Høiland-Jørgensen 	 * program is (re-)attached to another target.
35114a1e7c0cSToke Høiland-Jørgensen 	 */
35124a1e7c0cSToke Høiland-Jørgensen 	if (prog->aux->dst_prog &&
35134a1e7c0cSToke Høiland-Jørgensen 	    (tgt_prog_fd || tr != prog->aux->dst_trampoline))
35144a1e7c0cSToke Høiland-Jørgensen 		/* got extra prog ref from syscall, or attaching to different prog */
35154a1e7c0cSToke Høiland-Jørgensen 		bpf_prog_put(prog->aux->dst_prog);
35164a1e7c0cSToke Høiland-Jørgensen 	if (prog->aux->dst_trampoline && tr != prog->aux->dst_trampoline)
35174a1e7c0cSToke Høiland-Jørgensen 		/* we allocated a new trampoline, so free the old one */
35184a1e7c0cSToke Høiland-Jørgensen 		bpf_trampoline_put(prog->aux->dst_trampoline);
35194a1e7c0cSToke Høiland-Jørgensen 
35203aac1eadSToke Høiland-Jørgensen 	prog->aux->dst_prog = NULL;
35213aac1eadSToke Høiland-Jørgensen 	prog->aux->dst_trampoline = NULL;
35223aac1eadSToke Høiland-Jørgensen 	mutex_unlock(&prog->aux->dst_mutex);
35233aac1eadSToke Høiland-Jørgensen 
3524a3b80e10SAndrii Nakryiko 	return bpf_link_settle(&link_primer);
35253aac1eadSToke Høiland-Jørgensen out_unlock:
35264a1e7c0cSToke Høiland-Jørgensen 	if (tr && tr != prog->aux->dst_trampoline)
35274a1e7c0cSToke Høiland-Jørgensen 		bpf_trampoline_put(tr);
35283aac1eadSToke Høiland-Jørgensen 	mutex_unlock(&prog->aux->dst_mutex);
35293aac1eadSToke Høiland-Jørgensen 	kfree(link);
3530fec56f58SAlexei Starovoitov out_put_prog:
35314a1e7c0cSToke Høiland-Jørgensen 	if (tgt_prog_fd && tgt_prog)
35324a1e7c0cSToke Høiland-Jørgensen 		bpf_prog_put(tgt_prog);
3533fec56f58SAlexei Starovoitov 	return err;
3534fec56f58SAlexei Starovoitov }
3535fec56f58SAlexei Starovoitov 
bpf_raw_tp_link_release(struct bpf_link * link)353670ed506cSAndrii Nakryiko static void bpf_raw_tp_link_release(struct bpf_link *link)
3537c4f6699dSAlexei Starovoitov {
353870ed506cSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp =
353970ed506cSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3540c4f6699dSAlexei Starovoitov 
3541d4dfc570SAndrii Nakryiko 	bpf_probe_unregister(raw_tp->btp, raw_tp);
3542a38d1107SMatt Mullins 	bpf_put_raw_tracepoint(raw_tp->btp);
3543babf3164SAndrii Nakryiko }
3544babf3164SAndrii Nakryiko 
bpf_raw_tp_link_dealloc(struct bpf_link * link)3545babf3164SAndrii Nakryiko static void bpf_raw_tp_link_dealloc(struct bpf_link *link)
3546babf3164SAndrii Nakryiko {
3547babf3164SAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp =
3548babf3164SAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3549babf3164SAndrii Nakryiko 
3550c4f6699dSAlexei Starovoitov 	kfree(raw_tp);
3551c4f6699dSAlexei Starovoitov }
3552c4f6699dSAlexei Starovoitov 
bpf_raw_tp_link_show_fdinfo(const struct bpf_link * link,struct seq_file * seq)3553f2e10bffSAndrii Nakryiko static void bpf_raw_tp_link_show_fdinfo(const struct bpf_link *link,
3554f2e10bffSAndrii Nakryiko 					struct seq_file *seq)
3555f2e10bffSAndrii Nakryiko {
3556f2e10bffSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp_link =
3557f2e10bffSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3558f2e10bffSAndrii Nakryiko 
3559f2e10bffSAndrii Nakryiko 	seq_printf(seq,
3560f2e10bffSAndrii Nakryiko 		   "tp_name:\t%s\n",
3561f2e10bffSAndrii Nakryiko 		   raw_tp_link->btp->tp->name);
3562f2e10bffSAndrii Nakryiko }
3563f2e10bffSAndrii Nakryiko 
bpf_copy_to_user(char __user * ubuf,const char * buf,u32 ulen,u32 len)356457d48537SYafang Shao static int bpf_copy_to_user(char __user *ubuf, const char *buf, u32 ulen,
356557d48537SYafang Shao 			    u32 len)
356657d48537SYafang Shao {
356757d48537SYafang Shao 	if (ulen >= len + 1) {
356857d48537SYafang Shao 		if (copy_to_user(ubuf, buf, len + 1))
356957d48537SYafang Shao 			return -EFAULT;
357057d48537SYafang Shao 	} else {
357157d48537SYafang Shao 		char zero = '\0';
357257d48537SYafang Shao 
357357d48537SYafang Shao 		if (copy_to_user(ubuf, buf, ulen - 1))
357457d48537SYafang Shao 			return -EFAULT;
357557d48537SYafang Shao 		if (put_user(zero, ubuf + ulen - 1))
357657d48537SYafang Shao 			return -EFAULT;
357757d48537SYafang Shao 		return -ENOSPC;
357857d48537SYafang Shao 	}
357957d48537SYafang Shao 
358057d48537SYafang Shao 	return 0;
358157d48537SYafang Shao }
358257d48537SYafang Shao 
bpf_raw_tp_link_fill_link_info(const struct bpf_link * link,struct bpf_link_info * info)3583f2e10bffSAndrii Nakryiko static int bpf_raw_tp_link_fill_link_info(const struct bpf_link *link,
3584f2e10bffSAndrii Nakryiko 					  struct bpf_link_info *info)
3585f2e10bffSAndrii Nakryiko {
3586f2e10bffSAndrii Nakryiko 	struct bpf_raw_tp_link *raw_tp_link =
3587f2e10bffSAndrii Nakryiko 		container_of(link, struct bpf_raw_tp_link, link);
3588f2e10bffSAndrii Nakryiko 	char __user *ubuf = u64_to_user_ptr(info->raw_tracepoint.tp_name);
3589f2e10bffSAndrii Nakryiko 	const char *tp_name = raw_tp_link->btp->tp->name;
3590f2e10bffSAndrii Nakryiko 	u32 ulen = info->raw_tracepoint.tp_name_len;
3591f2e10bffSAndrii Nakryiko 	size_t tp_len = strlen(tp_name);
3592f2e10bffSAndrii Nakryiko 
3593b474959dSYonghong Song 	if (!ulen ^ !ubuf)
3594f2e10bffSAndrii Nakryiko 		return -EINVAL;
3595f2e10bffSAndrii Nakryiko 
3596f2e10bffSAndrii Nakryiko 	info->raw_tracepoint.tp_name_len = tp_len + 1;
3597f2e10bffSAndrii Nakryiko 
3598f2e10bffSAndrii Nakryiko 	if (!ubuf)
3599f2e10bffSAndrii Nakryiko 		return 0;
3600f2e10bffSAndrii Nakryiko 
360157d48537SYafang Shao 	return bpf_copy_to_user(ubuf, tp_name, ulen, tp_len);
3602f2e10bffSAndrii Nakryiko }
3603f2e10bffSAndrii Nakryiko 
3604a3b80e10SAndrii Nakryiko static const struct bpf_link_ops bpf_raw_tp_link_lops = {
360570ed506cSAndrii Nakryiko 	.release = bpf_raw_tp_link_release,
36061a80dbcbSAndrii Nakryiko 	.dealloc_deferred = bpf_raw_tp_link_dealloc,
3607f2e10bffSAndrii Nakryiko 	.show_fdinfo = bpf_raw_tp_link_show_fdinfo,
3608f2e10bffSAndrii Nakryiko 	.fill_link_info = bpf_raw_tp_link_fill_link_info,
3609c4f6699dSAlexei Starovoitov };
3610c4f6699dSAlexei Starovoitov 
3611b89fbfbbSAndrii Nakryiko #ifdef CONFIG_PERF_EVENTS
3612b89fbfbbSAndrii Nakryiko struct bpf_perf_link {
3613b89fbfbbSAndrii Nakryiko 	struct bpf_link link;
3614b89fbfbbSAndrii Nakryiko 	struct file *perf_file;
3615b89fbfbbSAndrii Nakryiko };
3616b89fbfbbSAndrii Nakryiko 
bpf_perf_link_release(struct bpf_link * link)3617b89fbfbbSAndrii Nakryiko static void bpf_perf_link_release(struct bpf_link *link)
3618b89fbfbbSAndrii Nakryiko {
3619b89fbfbbSAndrii Nakryiko 	struct bpf_perf_link *perf_link = container_of(link, struct bpf_perf_link, link);
3620b89fbfbbSAndrii Nakryiko 	struct perf_event *event = perf_link->perf_file->private_data;
3621b89fbfbbSAndrii Nakryiko 
3622b89fbfbbSAndrii Nakryiko 	perf_event_free_bpf_prog(event);
3623b89fbfbbSAndrii Nakryiko 	fput(perf_link->perf_file);
3624b89fbfbbSAndrii Nakryiko }
3625b89fbfbbSAndrii Nakryiko 
bpf_perf_link_dealloc(struct bpf_link * link)3626b89fbfbbSAndrii Nakryiko static void bpf_perf_link_dealloc(struct bpf_link *link)
3627b89fbfbbSAndrii Nakryiko {
3628b89fbfbbSAndrii Nakryiko 	struct bpf_perf_link *perf_link = container_of(link, struct bpf_perf_link, link);
3629b89fbfbbSAndrii Nakryiko 
3630b89fbfbbSAndrii Nakryiko 	kfree(perf_link);
3631b89fbfbbSAndrii Nakryiko }
3632b89fbfbbSAndrii Nakryiko 
bpf_perf_link_fill_common(const struct perf_event * event,char __user * uname,u32 ulen,u64 * probe_offset,u64 * probe_addr,u32 * fd_type,unsigned long * missed)36331b715e1bSYafang Shao static int bpf_perf_link_fill_common(const struct perf_event *event,
36341b715e1bSYafang Shao 				     char __user *uname, u32 ulen,
36351b715e1bSYafang Shao 				     u64 *probe_offset, u64 *probe_addr,
36363acf8aceSJiri Olsa 				     u32 *fd_type, unsigned long *missed)
36371b715e1bSYafang Shao {
36381b715e1bSYafang Shao 	const char *buf;
36391b715e1bSYafang Shao 	u32 prog_id;
36401b715e1bSYafang Shao 	size_t len;
36411b715e1bSYafang Shao 	int err;
36421b715e1bSYafang Shao 
36431b715e1bSYafang Shao 	if (!ulen ^ !uname)
36441b715e1bSYafang Shao 		return -EINVAL;
36451b715e1bSYafang Shao 
36461b715e1bSYafang Shao 	err = bpf_get_perf_event_info(event, &prog_id, fd_type, &buf,
36473acf8aceSJiri Olsa 				      probe_offset, probe_addr, missed);
36481b715e1bSYafang Shao 	if (err)
36491b715e1bSYafang Shao 		return err;
36500aa35162SYafang Shao 	if (!uname)
36510aa35162SYafang Shao 		return 0;
36521b715e1bSYafang Shao 	if (buf) {
36531b715e1bSYafang Shao 		len = strlen(buf);
36541b715e1bSYafang Shao 		err = bpf_copy_to_user(uname, buf, ulen, len);
36551b715e1bSYafang Shao 		if (err)
36561b715e1bSYafang Shao 			return err;
36571b715e1bSYafang Shao 	} else {
36581b715e1bSYafang Shao 		char zero = '\0';
36591b715e1bSYafang Shao 
36601b715e1bSYafang Shao 		if (put_user(zero, uname))
36611b715e1bSYafang Shao 			return -EFAULT;
36621b715e1bSYafang Shao 	}
36631b715e1bSYafang Shao 	return 0;
36641b715e1bSYafang Shao }
36651b715e1bSYafang Shao 
36661b715e1bSYafang Shao #ifdef CONFIG_KPROBE_EVENTS
bpf_perf_link_fill_kprobe(const struct perf_event * event,struct bpf_link_info * info)36671b715e1bSYafang Shao static int bpf_perf_link_fill_kprobe(const struct perf_event *event,
36681b715e1bSYafang Shao 				     struct bpf_link_info *info)
36691b715e1bSYafang Shao {
36703acf8aceSJiri Olsa 	unsigned long missed;
36711b715e1bSYafang Shao 	char __user *uname;
36721b715e1bSYafang Shao 	u64 addr, offset;
36731b715e1bSYafang Shao 	u32 ulen, type;
36741b715e1bSYafang Shao 	int err;
36751b715e1bSYafang Shao 
36761b715e1bSYafang Shao 	uname = u64_to_user_ptr(info->perf_event.kprobe.func_name);
36771b715e1bSYafang Shao 	ulen = info->perf_event.kprobe.name_len;
36781b715e1bSYafang Shao 	err = bpf_perf_link_fill_common(event, uname, ulen, &offset, &addr,
36793acf8aceSJiri Olsa 					&type, &missed);
36801b715e1bSYafang Shao 	if (err)
36811b715e1bSYafang Shao 		return err;
36821b715e1bSYafang Shao 	if (type == BPF_FD_TYPE_KRETPROBE)
36831b715e1bSYafang Shao 		info->perf_event.type = BPF_PERF_EVENT_KRETPROBE;
36841b715e1bSYafang Shao 	else
36851b715e1bSYafang Shao 		info->perf_event.type = BPF_PERF_EVENT_KPROBE;
36861b715e1bSYafang Shao 
36871b715e1bSYafang Shao 	info->perf_event.kprobe.offset = offset;
36883acf8aceSJiri Olsa 	info->perf_event.kprobe.missed = missed;
36891b715e1bSYafang Shao 	if (!kallsyms_show_value(current_cred()))
36901b715e1bSYafang Shao 		addr = 0;
36911b715e1bSYafang Shao 	info->perf_event.kprobe.addr = addr;
3692d5c16492SJiri Olsa 	info->perf_event.kprobe.cookie = event->bpf_cookie;
36931b715e1bSYafang Shao 	return 0;
36941b715e1bSYafang Shao }
36951b715e1bSYafang Shao #endif
36961b715e1bSYafang Shao 
36971b715e1bSYafang Shao #ifdef CONFIG_UPROBE_EVENTS
bpf_perf_link_fill_uprobe(const struct perf_event * event,struct bpf_link_info * info)36981b715e1bSYafang Shao static int bpf_perf_link_fill_uprobe(const struct perf_event *event,
36991b715e1bSYafang Shao 				     struct bpf_link_info *info)
37001b715e1bSYafang Shao {
37011b715e1bSYafang Shao 	char __user *uname;
37021b715e1bSYafang Shao 	u64 addr, offset;
37031b715e1bSYafang Shao 	u32 ulen, type;
37041b715e1bSYafang Shao 	int err;
37051b715e1bSYafang Shao 
37061b715e1bSYafang Shao 	uname = u64_to_user_ptr(info->perf_event.uprobe.file_name);
37071b715e1bSYafang Shao 	ulen = info->perf_event.uprobe.name_len;
37081b715e1bSYafang Shao 	err = bpf_perf_link_fill_common(event, uname, ulen, &offset, &addr,
37093acf8aceSJiri Olsa 					&type, NULL);
37101b715e1bSYafang Shao 	if (err)
37111b715e1bSYafang Shao 		return err;
37121b715e1bSYafang Shao 
37131b715e1bSYafang Shao 	if (type == BPF_FD_TYPE_URETPROBE)
37141b715e1bSYafang Shao 		info->perf_event.type = BPF_PERF_EVENT_URETPROBE;
37151b715e1bSYafang Shao 	else
37161b715e1bSYafang Shao 		info->perf_event.type = BPF_PERF_EVENT_UPROBE;
37171b715e1bSYafang Shao 	info->perf_event.uprobe.offset = offset;
3718d5c16492SJiri Olsa 	info->perf_event.uprobe.cookie = event->bpf_cookie;
37191b715e1bSYafang Shao 	return 0;
37201b715e1bSYafang Shao }
37211b715e1bSYafang Shao #endif
37221b715e1bSYafang Shao 
bpf_perf_link_fill_probe(const struct perf_event * event,struct bpf_link_info * info)37231b715e1bSYafang Shao static int bpf_perf_link_fill_probe(const struct perf_event *event,
37241b715e1bSYafang Shao 				    struct bpf_link_info *info)
37251b715e1bSYafang Shao {
37261b715e1bSYafang Shao #ifdef CONFIG_KPROBE_EVENTS
37271b715e1bSYafang Shao 	if (event->tp_event->flags & TRACE_EVENT_FL_KPROBE)
37281b715e1bSYafang Shao 		return bpf_perf_link_fill_kprobe(event, info);
37291b715e1bSYafang Shao #endif
37301b715e1bSYafang Shao #ifdef CONFIG_UPROBE_EVENTS
37311b715e1bSYafang Shao 	if (event->tp_event->flags & TRACE_EVENT_FL_UPROBE)
37321b715e1bSYafang Shao 		return bpf_perf_link_fill_uprobe(event, info);
37331b715e1bSYafang Shao #endif
37341b715e1bSYafang Shao 	return -EOPNOTSUPP;
37351b715e1bSYafang Shao }
37361b715e1bSYafang Shao 
bpf_perf_link_fill_tracepoint(const struct perf_event * event,struct bpf_link_info * info)37371b715e1bSYafang Shao static int bpf_perf_link_fill_tracepoint(const struct perf_event *event,
37381b715e1bSYafang Shao 					 struct bpf_link_info *info)
37391b715e1bSYafang Shao {
37401b715e1bSYafang Shao 	char __user *uname;
37411b715e1bSYafang Shao 	u32 ulen;
37421b715e1bSYafang Shao 
37431b715e1bSYafang Shao 	uname = u64_to_user_ptr(info->perf_event.tracepoint.tp_name);
37441b715e1bSYafang Shao 	ulen = info->perf_event.tracepoint.name_len;
37451b715e1bSYafang Shao 	info->perf_event.type = BPF_PERF_EVENT_TRACEPOINT;
3746d5c16492SJiri Olsa 	info->perf_event.tracepoint.cookie = event->bpf_cookie;
37473acf8aceSJiri Olsa 	return bpf_perf_link_fill_common(event, uname, ulen, NULL, NULL, NULL, NULL);
37481b715e1bSYafang Shao }
37491b715e1bSYafang Shao 
bpf_perf_link_fill_perf_event(const struct perf_event * event,struct bpf_link_info * info)37501b715e1bSYafang Shao static int bpf_perf_link_fill_perf_event(const struct perf_event *event,
37511b715e1bSYafang Shao 					 struct bpf_link_info *info)
37521b715e1bSYafang Shao {
37531b715e1bSYafang Shao 	info->perf_event.event.type = event->attr.type;
37541b715e1bSYafang Shao 	info->perf_event.event.config = event->attr.config;
3755d5c16492SJiri Olsa 	info->perf_event.event.cookie = event->bpf_cookie;
37561b715e1bSYafang Shao 	info->perf_event.type = BPF_PERF_EVENT_EVENT;
37571b715e1bSYafang Shao 	return 0;
37581b715e1bSYafang Shao }
37591b715e1bSYafang Shao 
bpf_perf_link_fill_link_info(const struct bpf_link * link,struct bpf_link_info * info)37601b715e1bSYafang Shao static int bpf_perf_link_fill_link_info(const struct bpf_link *link,
37611b715e1bSYafang Shao 					struct bpf_link_info *info)
37621b715e1bSYafang Shao {
37631b715e1bSYafang Shao 	struct bpf_perf_link *perf_link;
37641b715e1bSYafang Shao 	const struct perf_event *event;
37651b715e1bSYafang Shao 
37661b715e1bSYafang Shao 	perf_link = container_of(link, struct bpf_perf_link, link);
37671b715e1bSYafang Shao 	event = perf_get_event(perf_link->perf_file);
37681b715e1bSYafang Shao 	if (IS_ERR(event))
37691b715e1bSYafang Shao 		return PTR_ERR(event);
37701b715e1bSYafang Shao 
37711b715e1bSYafang Shao 	switch (event->prog->type) {
37721b715e1bSYafang Shao 	case BPF_PROG_TYPE_PERF_EVENT:
37731b715e1bSYafang Shao 		return bpf_perf_link_fill_perf_event(event, info);
37741b715e1bSYafang Shao 	case BPF_PROG_TYPE_TRACEPOINT:
37751b715e1bSYafang Shao 		return bpf_perf_link_fill_tracepoint(event, info);
37761b715e1bSYafang Shao 	case BPF_PROG_TYPE_KPROBE:
37771b715e1bSYafang Shao 		return bpf_perf_link_fill_probe(event, info);
37781b715e1bSYafang Shao 	default:
37791b715e1bSYafang Shao 		return -EOPNOTSUPP;
37801b715e1bSYafang Shao 	}
37811b715e1bSYafang Shao }
37821b715e1bSYafang Shao 
3783b89fbfbbSAndrii Nakryiko static const struct bpf_link_ops bpf_perf_link_lops = {
3784b89fbfbbSAndrii Nakryiko 	.release = bpf_perf_link_release,
3785b89fbfbbSAndrii Nakryiko 	.dealloc = bpf_perf_link_dealloc,
37861b715e1bSYafang Shao 	.fill_link_info = bpf_perf_link_fill_link_info,
3787b89fbfbbSAndrii Nakryiko };
3788b89fbfbbSAndrii Nakryiko 
bpf_perf_link_attach(const union bpf_attr * attr,struct bpf_prog * prog)3789b89fbfbbSAndrii Nakryiko static int bpf_perf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
3790b89fbfbbSAndrii Nakryiko {
3791b89fbfbbSAndrii Nakryiko 	struct bpf_link_primer link_primer;
3792b89fbfbbSAndrii Nakryiko 	struct bpf_perf_link *link;
3793b89fbfbbSAndrii Nakryiko 	struct perf_event *event;
3794b89fbfbbSAndrii Nakryiko 	struct file *perf_file;
3795b89fbfbbSAndrii Nakryiko 	int err;
3796b89fbfbbSAndrii Nakryiko 
3797b89fbfbbSAndrii Nakryiko 	if (attr->link_create.flags)
3798b89fbfbbSAndrii Nakryiko 		return -EINVAL;
3799b89fbfbbSAndrii Nakryiko 
3800b89fbfbbSAndrii Nakryiko 	perf_file = perf_event_get(attr->link_create.target_fd);
3801b89fbfbbSAndrii Nakryiko 	if (IS_ERR(perf_file))
3802b89fbfbbSAndrii Nakryiko 		return PTR_ERR(perf_file);
3803b89fbfbbSAndrii Nakryiko 
3804b89fbfbbSAndrii Nakryiko 	link = kzalloc(sizeof(*link), GFP_USER);
3805b89fbfbbSAndrii Nakryiko 	if (!link) {
3806b89fbfbbSAndrii Nakryiko 		err = -ENOMEM;
3807b89fbfbbSAndrii Nakryiko 		goto out_put_file;
3808b89fbfbbSAndrii Nakryiko 	}
3809b89fbfbbSAndrii Nakryiko 	bpf_link_init(&link->link, BPF_LINK_TYPE_PERF_EVENT, &bpf_perf_link_lops, prog);
3810b89fbfbbSAndrii Nakryiko 	link->perf_file = perf_file;
3811b89fbfbbSAndrii Nakryiko 
3812b89fbfbbSAndrii Nakryiko 	err = bpf_link_prime(&link->link, &link_primer);
3813b89fbfbbSAndrii Nakryiko 	if (err) {
3814b89fbfbbSAndrii Nakryiko 		kfree(link);
3815b89fbfbbSAndrii Nakryiko 		goto out_put_file;
3816b89fbfbbSAndrii Nakryiko 	}
3817b89fbfbbSAndrii Nakryiko 
3818b89fbfbbSAndrii Nakryiko 	event = perf_file->private_data;
381982e6b1eeSAndrii Nakryiko 	err = perf_event_set_bpf_prog(event, prog, attr->link_create.perf_event.bpf_cookie);
3820b89fbfbbSAndrii Nakryiko 	if (err) {
3821b89fbfbbSAndrii Nakryiko 		bpf_link_cleanup(&link_primer);
3822b89fbfbbSAndrii Nakryiko 		goto out_put_file;
3823b89fbfbbSAndrii Nakryiko 	}
3824b89fbfbbSAndrii Nakryiko 	/* perf_event_set_bpf_prog() doesn't take its own refcnt on prog */
3825b89fbfbbSAndrii Nakryiko 	bpf_prog_inc(prog);
3826b89fbfbbSAndrii Nakryiko 
3827b89fbfbbSAndrii Nakryiko 	return bpf_link_settle(&link_primer);
3828b89fbfbbSAndrii Nakryiko 
3829b89fbfbbSAndrii Nakryiko out_put_file:
3830b89fbfbbSAndrii Nakryiko 	fput(perf_file);
3831b89fbfbbSAndrii Nakryiko 	return err;
3832b89fbfbbSAndrii Nakryiko }
38330dcac272SJiri Olsa #else
bpf_perf_link_attach(const union bpf_attr * attr,struct bpf_prog * prog)38340dcac272SJiri Olsa static int bpf_perf_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
38350dcac272SJiri Olsa {
38360dcac272SJiri Olsa 	return -EOPNOTSUPP;
38370dcac272SJiri Olsa }
3838b89fbfbbSAndrii Nakryiko #endif /* CONFIG_PERF_EVENTS */
3839b89fbfbbSAndrii Nakryiko 
bpf_raw_tp_link_attach(struct bpf_prog * prog,const char __user * user_tp_name,u64 cookie)3840df86ca0dSAndrii Nakryiko static int bpf_raw_tp_link_attach(struct bpf_prog *prog,
384168ca5d4eSAndrii Nakryiko 				  const char __user *user_tp_name, u64 cookie)
3842c4f6699dSAlexei Starovoitov {
3843a3b80e10SAndrii Nakryiko 	struct bpf_link_primer link_primer;
3844babf3164SAndrii Nakryiko 	struct bpf_raw_tp_link *link;
3845c4f6699dSAlexei Starovoitov 	struct bpf_raw_event_map *btp;
3846ac4414b5SAlexei Starovoitov 	const char *tp_name;
3847ac4414b5SAlexei Starovoitov 	char buf[128];
3848a3b80e10SAndrii Nakryiko 	int err;
3849c4f6699dSAlexei Starovoitov 
38509e4e01dfSKP Singh 	switch (prog->type) {
38519e4e01dfSKP Singh 	case BPF_PROG_TYPE_TRACING:
38529e4e01dfSKP Singh 	case BPF_PROG_TYPE_EXT:
38539e4e01dfSKP Singh 	case BPF_PROG_TYPE_LSM:
3854df86ca0dSAndrii Nakryiko 		if (user_tp_name)
3855fec56f58SAlexei Starovoitov 			/* The attach point for this category of programs
3856fec56f58SAlexei Starovoitov 			 * should be specified via btf_id during program load.
3857ac4414b5SAlexei Starovoitov 			 */
3858df86ca0dSAndrii Nakryiko 			return -EINVAL;
38599e4e01dfSKP Singh 		if (prog->type == BPF_PROG_TYPE_TRACING &&
38609e4e01dfSKP Singh 		    prog->expected_attach_type == BPF_TRACE_RAW_TP) {
386138207291SMartin KaFai Lau 			tp_name = prog->aux->attach_func_name;
38629e4e01dfSKP Singh 			break;
38639e4e01dfSKP Singh 		}
38642fcc8241SKui-Feng Lee 		return bpf_tracing_prog_attach(prog, 0, 0, 0);
38659e4e01dfSKP Singh 	case BPF_PROG_TYPE_RAW_TRACEPOINT:
38669e4e01dfSKP Singh 	case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE:
3867df86ca0dSAndrii Nakryiko 		if (strncpy_from_user(buf, user_tp_name, sizeof(buf) - 1) < 0)
3868df86ca0dSAndrii Nakryiko 			return -EFAULT;
3869ac4414b5SAlexei Starovoitov 		buf[sizeof(buf) - 1] = 0;
3870ac4414b5SAlexei Starovoitov 		tp_name = buf;
38719e4e01dfSKP Singh 		break;
38729e4e01dfSKP Singh 	default:
3873df86ca0dSAndrii Nakryiko 		return -EINVAL;
3874ac4414b5SAlexei Starovoitov 	}
3875c4f6699dSAlexei Starovoitov 
3876a38d1107SMatt Mullins 	btp = bpf_get_raw_tracepoint(tp_name);
3877df86ca0dSAndrii Nakryiko 	if (!btp)
3878df86ca0dSAndrii Nakryiko 		return -ENOENT;
3879c4f6699dSAlexei Starovoitov 
3880babf3164SAndrii Nakryiko 	link = kzalloc(sizeof(*link), GFP_USER);
3881babf3164SAndrii Nakryiko 	if (!link) {
3882a38d1107SMatt Mullins 		err = -ENOMEM;
3883a38d1107SMatt Mullins 		goto out_put_btp;
3884a38d1107SMatt Mullins 	}
3885f2e10bffSAndrii Nakryiko 	bpf_link_init(&link->link, BPF_LINK_TYPE_RAW_TRACEPOINT,
3886f2e10bffSAndrii Nakryiko 		      &bpf_raw_tp_link_lops, prog);
3887babf3164SAndrii Nakryiko 	link->btp = btp;
388868ca5d4eSAndrii Nakryiko 	link->cookie = cookie;
3889c4f6699dSAlexei Starovoitov 
3890a3b80e10SAndrii Nakryiko 	err = bpf_link_prime(&link->link, &link_primer);
3891a3b80e10SAndrii Nakryiko 	if (err) {
3892babf3164SAndrii Nakryiko 		kfree(link);
3893babf3164SAndrii Nakryiko 		goto out_put_btp;
3894c4f6699dSAlexei Starovoitov 	}
3895babf3164SAndrii Nakryiko 
3896d4dfc570SAndrii Nakryiko 	err = bpf_probe_register(link->btp, link);
3897babf3164SAndrii Nakryiko 	if (err) {
3898a3b80e10SAndrii Nakryiko 		bpf_link_cleanup(&link_primer);
3899babf3164SAndrii Nakryiko 		goto out_put_btp;
3900babf3164SAndrii Nakryiko 	}
3901babf3164SAndrii Nakryiko 
3902a3b80e10SAndrii Nakryiko 	return bpf_link_settle(&link_primer);
3903c4f6699dSAlexei Starovoitov 
3904a38d1107SMatt Mullins out_put_btp:
3905a38d1107SMatt Mullins 	bpf_put_raw_tracepoint(btp);
3906c4f6699dSAlexei Starovoitov 	return err;
3907c4f6699dSAlexei Starovoitov }
3908c4f6699dSAlexei Starovoitov 
390968ca5d4eSAndrii Nakryiko #define BPF_RAW_TRACEPOINT_OPEN_LAST_FIELD raw_tracepoint.cookie
3910df86ca0dSAndrii Nakryiko 
bpf_raw_tracepoint_open(const union bpf_attr * attr)3911df86ca0dSAndrii Nakryiko static int bpf_raw_tracepoint_open(const union bpf_attr *attr)
3912df86ca0dSAndrii Nakryiko {
3913df86ca0dSAndrii Nakryiko 	struct bpf_prog *prog;
391468ca5d4eSAndrii Nakryiko 	void __user *tp_name;
391568ca5d4eSAndrii Nakryiko 	__u64 cookie;
3916df86ca0dSAndrii Nakryiko 	int fd;
3917df86ca0dSAndrii Nakryiko 
3918df86ca0dSAndrii Nakryiko 	if (CHECK_ATTR(BPF_RAW_TRACEPOINT_OPEN))
3919df86ca0dSAndrii Nakryiko 		return -EINVAL;
3920df86ca0dSAndrii Nakryiko 
3921df86ca0dSAndrii Nakryiko 	prog = bpf_prog_get(attr->raw_tracepoint.prog_fd);
3922df86ca0dSAndrii Nakryiko 	if (IS_ERR(prog))
3923df86ca0dSAndrii Nakryiko 		return PTR_ERR(prog);
3924df86ca0dSAndrii Nakryiko 
392568ca5d4eSAndrii Nakryiko 	tp_name = u64_to_user_ptr(attr->raw_tracepoint.name);
392668ca5d4eSAndrii Nakryiko 	cookie = attr->raw_tracepoint.cookie;
392768ca5d4eSAndrii Nakryiko 	fd = bpf_raw_tp_link_attach(prog, tp_name, cookie);
3928df86ca0dSAndrii Nakryiko 	if (fd < 0)
3929df86ca0dSAndrii Nakryiko 		bpf_prog_put(prog);
3930df86ca0dSAndrii Nakryiko 	return fd;
3931df86ca0dSAndrii Nakryiko }
3932df86ca0dSAndrii Nakryiko 
3933e28784e3SAndrii Nakryiko static enum bpf_prog_type
attach_type_to_prog_type(enum bpf_attach_type attach_type)3934e28784e3SAndrii Nakryiko attach_type_to_prog_type(enum bpf_attach_type attach_type)
3935e28784e3SAndrii Nakryiko {
3936e28784e3SAndrii Nakryiko 	switch (attach_type) {
3937e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_INGRESS:
3938e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_EGRESS:
3939e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SKB;
3940e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET_SOCK_CREATE:
3941f5836749SStanislav Fomichev 	case BPF_CGROUP_INET_SOCK_RELEASE:
3942e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_POST_BIND:
3943e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_POST_BIND:
3944e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCK;
3945e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_BIND:
3946e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_BIND:
3947e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET4_CONNECT:
3948e28784e3SAndrii Nakryiko 	case BPF_CGROUP_INET6_CONNECT:
3949859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_CONNECT:
39501b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETPEERNAME:
39511b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETPEERNAME:
3952859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_GETPEERNAME:
39531b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETSOCKNAME:
39541b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETSOCKNAME:
3955859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_GETSOCKNAME:
3956e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP4_SENDMSG:
3957e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP6_SENDMSG:
3958859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_SENDMSG:
3959e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP4_RECVMSG:
3960e28784e3SAndrii Nakryiko 	case BPF_CGROUP_UDP6_RECVMSG:
3961859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_RECVMSG:
3962e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCK_ADDR;
3963e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SOCK_OPS:
3964e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SOCK_OPS;
3965e28784e3SAndrii Nakryiko 	case BPF_CGROUP_DEVICE:
3966e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_DEVICE;
3967e28784e3SAndrii Nakryiko 	case BPF_SK_MSG_VERDICT:
3968e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SK_MSG;
3969e28784e3SAndrii Nakryiko 	case BPF_SK_SKB_STREAM_PARSER:
3970e28784e3SAndrii Nakryiko 	case BPF_SK_SKB_STREAM_VERDICT:
3971a7ba4558SCong Wang 	case BPF_SK_SKB_VERDICT:
3972e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_SK_SKB;
3973e28784e3SAndrii Nakryiko 	case BPF_LIRC_MODE2:
3974e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_LIRC_MODE2;
3975e28784e3SAndrii Nakryiko 	case BPF_FLOW_DISSECTOR:
3976e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_FLOW_DISSECTOR;
3977e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SYSCTL:
3978e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SYSCTL;
3979e28784e3SAndrii Nakryiko 	case BPF_CGROUP_GETSOCKOPT:
3980e28784e3SAndrii Nakryiko 	case BPF_CGROUP_SETSOCKOPT:
3981e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_CGROUP_SOCKOPT;
3982de4e05caSYonghong Song 	case BPF_TRACE_ITER:
3983df86ca0dSAndrii Nakryiko 	case BPF_TRACE_RAW_TP:
3984df86ca0dSAndrii Nakryiko 	case BPF_TRACE_FENTRY:
3985df86ca0dSAndrii Nakryiko 	case BPF_TRACE_FEXIT:
3986df86ca0dSAndrii Nakryiko 	case BPF_MODIFY_RETURN:
3987de4e05caSYonghong Song 		return BPF_PROG_TYPE_TRACING;
3988df86ca0dSAndrii Nakryiko 	case BPF_LSM_MAC:
3989df86ca0dSAndrii Nakryiko 		return BPF_PROG_TYPE_LSM;
3990e9ddbb77SJakub Sitnicki 	case BPF_SK_LOOKUP:
3991e9ddbb77SJakub Sitnicki 		return BPF_PROG_TYPE_SK_LOOKUP;
3992aa8d3a71SAndrii Nakryiko 	case BPF_XDP:
3993aa8d3a71SAndrii Nakryiko 		return BPF_PROG_TYPE_XDP;
399469fd337aSStanislav Fomichev 	case BPF_LSM_CGROUP:
399569fd337aSStanislav Fomichev 		return BPF_PROG_TYPE_LSM;
3996e420bed0SDaniel Borkmann 	case BPF_TCX_INGRESS:
3997e420bed0SDaniel Borkmann 	case BPF_TCX_EGRESS:
399835dfaad7SDaniel Borkmann 	case BPF_NETKIT_PRIMARY:
399935dfaad7SDaniel Borkmann 	case BPF_NETKIT_PEER:
4000e420bed0SDaniel Borkmann 		return BPF_PROG_TYPE_SCHED_CLS;
4001e28784e3SAndrii Nakryiko 	default:
4002e28784e3SAndrii Nakryiko 		return BPF_PROG_TYPE_UNSPEC;
4003e28784e3SAndrii Nakryiko 	}
4004e28784e3SAndrii Nakryiko }
4005e28784e3SAndrii Nakryiko 
bpf_prog_attach_check_attach_type(const struct bpf_prog * prog,enum bpf_attach_type attach_type)40063505cb9fSJiri Olsa static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog,
40073505cb9fSJiri Olsa 					     enum bpf_attach_type attach_type)
40083505cb9fSJiri Olsa {
40093505cb9fSJiri Olsa 	enum bpf_prog_type ptype;
40103505cb9fSJiri Olsa 
40113505cb9fSJiri Olsa 	switch (prog->type) {
40123505cb9fSJiri Olsa 	case BPF_PROG_TYPE_CGROUP_SOCK:
40133505cb9fSJiri Olsa 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
40143505cb9fSJiri Olsa 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
40153505cb9fSJiri Olsa 	case BPF_PROG_TYPE_SK_LOOKUP:
40163505cb9fSJiri Olsa 		return attach_type == prog->expected_attach_type ? 0 : -EINVAL;
40173505cb9fSJiri Olsa 	case BPF_PROG_TYPE_CGROUP_SKB:
4018caf8f28eSAndrii Nakryiko 		if (!bpf_token_capable(prog->aux->token, CAP_NET_ADMIN))
40193505cb9fSJiri Olsa 			/* cg-skb progs can be loaded by unpriv user.
40203505cb9fSJiri Olsa 			 * check permissions at attach time.
40213505cb9fSJiri Olsa 			 */
40223505cb9fSJiri Olsa 			return -EPERM;
4023543576ecSStanislav Fomichev 
4024543576ecSStanislav Fomichev 		ptype = attach_type_to_prog_type(attach_type);
4025543576ecSStanislav Fomichev 		if (prog->type != ptype)
4026543576ecSStanislav Fomichev 			return -EINVAL;
4027543576ecSStanislav Fomichev 
40283505cb9fSJiri Olsa 		return prog->enforce_expected_attach_type &&
40293505cb9fSJiri Olsa 			prog->expected_attach_type != attach_type ?
40303505cb9fSJiri Olsa 			-EINVAL : 0;
40313505cb9fSJiri Olsa 	case BPF_PROG_TYPE_EXT:
40323505cb9fSJiri Olsa 		return 0;
40333505cb9fSJiri Olsa 	case BPF_PROG_TYPE_NETFILTER:
40343505cb9fSJiri Olsa 		if (attach_type != BPF_NETFILTER)
40353505cb9fSJiri Olsa 			return -EINVAL;
40363505cb9fSJiri Olsa 		return 0;
40373505cb9fSJiri Olsa 	case BPF_PROG_TYPE_PERF_EVENT:
40383505cb9fSJiri Olsa 	case BPF_PROG_TYPE_TRACEPOINT:
40393505cb9fSJiri Olsa 		if (attach_type != BPF_PERF_EVENT)
40403505cb9fSJiri Olsa 			return -EINVAL;
40413505cb9fSJiri Olsa 		return 0;
40423505cb9fSJiri Olsa 	case BPF_PROG_TYPE_KPROBE:
40433505cb9fSJiri Olsa 		if (prog->expected_attach_type == BPF_TRACE_KPROBE_MULTI &&
40443505cb9fSJiri Olsa 		    attach_type != BPF_TRACE_KPROBE_MULTI)
40453505cb9fSJiri Olsa 			return -EINVAL;
4046535a3692SJiri Olsa 		if (prog->expected_attach_type == BPF_TRACE_KPROBE_SESSION &&
4047535a3692SJiri Olsa 		    attach_type != BPF_TRACE_KPROBE_SESSION)
4048535a3692SJiri Olsa 			return -EINVAL;
404989ae89f5SJiri Olsa 		if (prog->expected_attach_type == BPF_TRACE_UPROBE_MULTI &&
405089ae89f5SJiri Olsa 		    attach_type != BPF_TRACE_UPROBE_MULTI)
405189ae89f5SJiri Olsa 			return -EINVAL;
40523505cb9fSJiri Olsa 		if (attach_type != BPF_PERF_EVENT &&
405389ae89f5SJiri Olsa 		    attach_type != BPF_TRACE_KPROBE_MULTI &&
4054535a3692SJiri Olsa 		    attach_type != BPF_TRACE_KPROBE_SESSION &&
405589ae89f5SJiri Olsa 		    attach_type != BPF_TRACE_UPROBE_MULTI)
40563505cb9fSJiri Olsa 			return -EINVAL;
40573505cb9fSJiri Olsa 		return 0;
40583505cb9fSJiri Olsa 	case BPF_PROG_TYPE_SCHED_CLS:
40593505cb9fSJiri Olsa 		if (attach_type != BPF_TCX_INGRESS &&
406035dfaad7SDaniel Borkmann 		    attach_type != BPF_TCX_EGRESS &&
406135dfaad7SDaniel Borkmann 		    attach_type != BPF_NETKIT_PRIMARY &&
406235dfaad7SDaniel Borkmann 		    attach_type != BPF_NETKIT_PEER)
40633505cb9fSJiri Olsa 			return -EINVAL;
40643505cb9fSJiri Olsa 		return 0;
40653505cb9fSJiri Olsa 	default:
40663505cb9fSJiri Olsa 		ptype = attach_type_to_prog_type(attach_type);
40673505cb9fSJiri Olsa 		if (ptype == BPF_PROG_TYPE_UNSPEC || ptype != prog->type)
40683505cb9fSJiri Olsa 			return -EINVAL;
40693505cb9fSJiri Olsa 		return 0;
40703505cb9fSJiri Olsa 	}
40713505cb9fSJiri Olsa }
40723505cb9fSJiri Olsa 
4073e420bed0SDaniel Borkmann #define BPF_PROG_ATTACH_LAST_FIELD expected_revision
4074174a79ffSJohn Fastabend 
4075e420bed0SDaniel Borkmann #define BPF_F_ATTACH_MASK_BASE	\
4076e420bed0SDaniel Borkmann 	(BPF_F_ALLOW_OVERRIDE |	\
4077e420bed0SDaniel Borkmann 	 BPF_F_ALLOW_MULTI |	\
4078e420bed0SDaniel Borkmann 	 BPF_F_REPLACE)
4079e420bed0SDaniel Borkmann 
4080e420bed0SDaniel Borkmann #define BPF_F_ATTACH_MASK_MPROG	\
4081e420bed0SDaniel Borkmann 	(BPF_F_REPLACE |	\
4082e420bed0SDaniel Borkmann 	 BPF_F_BEFORE |		\
4083e420bed0SDaniel Borkmann 	 BPF_F_AFTER |		\
4084e420bed0SDaniel Borkmann 	 BPF_F_ID |		\
4085e420bed0SDaniel Borkmann 	 BPF_F_LINK)
4086324bda9eSAlexei Starovoitov 
bpf_prog_attach(const union bpf_attr * attr)4087f4324551SDaniel Mack static int bpf_prog_attach(const union bpf_attr *attr)
4088f4324551SDaniel Mack {
40897f677633SAlexei Starovoitov 	enum bpf_prog_type ptype;
4090f4324551SDaniel Mack 	struct bpf_prog *prog;
40917f677633SAlexei Starovoitov 	int ret;
4092f4324551SDaniel Mack 
4093f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_ATTACH))
4094f4324551SDaniel Mack 		return -EINVAL;
4095f4324551SDaniel Mack 
4096e28784e3SAndrii Nakryiko 	ptype = attach_type_to_prog_type(attr->attach_type);
4097e28784e3SAndrii Nakryiko 	if (ptype == BPF_PROG_TYPE_UNSPEC)
4098b2cd1257SDavid Ahern 		return -EINVAL;
4099ba62d611SLorenz Bauer 	if (bpf_mprog_supported(ptype)) {
4100ba62d611SLorenz Bauer 		if (attr->attach_flags & ~BPF_F_ATTACH_MASK_MPROG)
4101e420bed0SDaniel Borkmann 			return -EINVAL;
4102ba62d611SLorenz Bauer 	} else {
4103ba62d611SLorenz Bauer 		if (attr->attach_flags & ~BPF_F_ATTACH_MASK_BASE)
4104ba62d611SLorenz Bauer 			return -EINVAL;
4105ba62d611SLorenz Bauer 		if (attr->relative_fd ||
4106ba62d611SLorenz Bauer 		    attr->expected_revision)
4107ba62d611SLorenz Bauer 			return -EINVAL;
4108ba62d611SLorenz Bauer 	}
4109b2cd1257SDavid Ahern 
4110b2cd1257SDavid Ahern 	prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
4111f4324551SDaniel Mack 	if (IS_ERR(prog))
4112f4324551SDaniel Mack 		return PTR_ERR(prog);
4113f4324551SDaniel Mack 
41145e43f899SAndrey Ignatov 	if (bpf_prog_attach_check_attach_type(prog, attr->attach_type)) {
41155e43f899SAndrey Ignatov 		bpf_prog_put(prog);
41165e43f899SAndrey Ignatov 		return -EINVAL;
41175e43f899SAndrey Ignatov 	}
41185e43f899SAndrey Ignatov 
4119fdb5c453SSean Young 	switch (ptype) {
4120fdb5c453SSean Young 	case BPF_PROG_TYPE_SK_SKB:
4121fdb5c453SSean Young 	case BPF_PROG_TYPE_SK_MSG:
4122604326b4SDaniel Borkmann 		ret = sock_map_get_from_fd(attr, prog);
4123fdb5c453SSean Young 		break;
4124fdb5c453SSean Young 	case BPF_PROG_TYPE_LIRC_MODE2:
4125fdb5c453SSean Young 		ret = lirc_prog_attach(attr, prog);
4126fdb5c453SSean Young 		break;
4127d58e468bSPetar Penkov 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
4128a3fd7ceeSJakub Sitnicki 		ret = netns_bpf_prog_attach(attr, prog);
4129d58e468bSPetar Penkov 		break;
4130e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
4131e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
4132e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
4133e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
4134e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
4135e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
4136e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
413769fd337aSStanislav Fomichev 	case BPF_PROG_TYPE_LSM:
413869fd337aSStanislav Fomichev 		if (ptype == BPF_PROG_TYPE_LSM &&
413969fd337aSStanislav Fomichev 		    prog->expected_attach_type != BPF_LSM_CGROUP)
4140e89f3edfSMilan Landaverde 			ret = -EINVAL;
4141e89f3edfSMilan Landaverde 		else
4142fdb5c453SSean Young 			ret = cgroup_bpf_prog_attach(attr, ptype, prog);
4143e28784e3SAndrii Nakryiko 		break;
4144e420bed0SDaniel Borkmann 	case BPF_PROG_TYPE_SCHED_CLS:
414535dfaad7SDaniel Borkmann 		if (attr->attach_type == BPF_TCX_INGRESS ||
414635dfaad7SDaniel Borkmann 		    attr->attach_type == BPF_TCX_EGRESS)
4147e420bed0SDaniel Borkmann 			ret = tcx_prog_attach(attr, prog);
414835dfaad7SDaniel Borkmann 		else
414935dfaad7SDaniel Borkmann 			ret = netkit_prog_attach(attr, prog);
4150e420bed0SDaniel Borkmann 		break;
4151e28784e3SAndrii Nakryiko 	default:
4152e28784e3SAndrii Nakryiko 		ret = -EINVAL;
4153f4324551SDaniel Mack 	}
4154f4324551SDaniel Mack 
41557f677633SAlexei Starovoitov 	if (ret)
41567f677633SAlexei Starovoitov 		bpf_prog_put(prog);
41577f677633SAlexei Starovoitov 	return ret;
4158f4324551SDaniel Mack }
4159f4324551SDaniel Mack 
4160e420bed0SDaniel Borkmann #define BPF_PROG_DETACH_LAST_FIELD expected_revision
4161f4324551SDaniel Mack 
bpf_prog_detach(const union bpf_attr * attr)4162f4324551SDaniel Mack static int bpf_prog_detach(const union bpf_attr *attr)
4163f4324551SDaniel Mack {
4164e420bed0SDaniel Borkmann 	struct bpf_prog *prog = NULL;
4165324bda9eSAlexei Starovoitov 	enum bpf_prog_type ptype;
4166e420bed0SDaniel Borkmann 	int ret;
4167f4324551SDaniel Mack 
4168f4324551SDaniel Mack 	if (CHECK_ATTR(BPF_PROG_DETACH))
4169f4324551SDaniel Mack 		return -EINVAL;
4170f4324551SDaniel Mack 
4171e28784e3SAndrii Nakryiko 	ptype = attach_type_to_prog_type(attr->attach_type);
4172e420bed0SDaniel Borkmann 	if (bpf_mprog_supported(ptype)) {
4173e420bed0SDaniel Borkmann 		if (ptype == BPF_PROG_TYPE_UNSPEC)
4174e420bed0SDaniel Borkmann 			return -EINVAL;
4175e420bed0SDaniel Borkmann 		if (attr->attach_flags & ~BPF_F_ATTACH_MASK_MPROG)
4176e420bed0SDaniel Borkmann 			return -EINVAL;
4177e420bed0SDaniel Borkmann 		if (attr->attach_bpf_fd) {
4178e420bed0SDaniel Borkmann 			prog = bpf_prog_get_type(attr->attach_bpf_fd, ptype);
4179e420bed0SDaniel Borkmann 			if (IS_ERR(prog))
4180e420bed0SDaniel Borkmann 				return PTR_ERR(prog);
4181e420bed0SDaniel Borkmann 		}
4182ba62d611SLorenz Bauer 	} else if (attr->attach_flags ||
4183ba62d611SLorenz Bauer 		   attr->relative_fd ||
4184ba62d611SLorenz Bauer 		   attr->expected_revision) {
4185ba62d611SLorenz Bauer 		return -EINVAL;
4186e420bed0SDaniel Borkmann 	}
4187e28784e3SAndrii Nakryiko 
4188e28784e3SAndrii Nakryiko 	switch (ptype) {
4189e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SK_MSG:
4190e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SK_SKB:
4191e420bed0SDaniel Borkmann 		ret = sock_map_prog_detach(attr, ptype);
4192e420bed0SDaniel Borkmann 		break;
4193e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_LIRC_MODE2:
4194e420bed0SDaniel Borkmann 		ret = lirc_prog_detach(attr);
4195e420bed0SDaniel Borkmann 		break;
4196e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
4197e420bed0SDaniel Borkmann 		ret = netns_bpf_prog_detach(attr, ptype);
4198e420bed0SDaniel Borkmann 		break;
4199e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
4200e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
4201e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
4202e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
4203e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
4204e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
4205e28784e3SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
420669fd337aSStanislav Fomichev 	case BPF_PROG_TYPE_LSM:
4207e420bed0SDaniel Borkmann 		ret = cgroup_bpf_prog_detach(attr, ptype);
4208e420bed0SDaniel Borkmann 		break;
4209e420bed0SDaniel Borkmann 	case BPF_PROG_TYPE_SCHED_CLS:
421035dfaad7SDaniel Borkmann 		if (attr->attach_type == BPF_TCX_INGRESS ||
421135dfaad7SDaniel Borkmann 		    attr->attach_type == BPF_TCX_EGRESS)
4212e420bed0SDaniel Borkmann 			ret = tcx_prog_detach(attr, prog);
421335dfaad7SDaniel Borkmann 		else
421435dfaad7SDaniel Borkmann 			ret = netkit_prog_detach(attr, prog);
4215e420bed0SDaniel Borkmann 		break;
4216f4324551SDaniel Mack 	default:
4217e420bed0SDaniel Borkmann 		ret = -EINVAL;
4218f4324551SDaniel Mack 	}
421940304b2aSLawrence Brakmo 
4220e420bed0SDaniel Borkmann 	if (prog)
4221e420bed0SDaniel Borkmann 		bpf_prog_put(prog);
4222e420bed0SDaniel Borkmann 	return ret;
4223e420bed0SDaniel Borkmann }
4224e420bed0SDaniel Borkmann 
4225a4fe7838SDaniel Borkmann #define BPF_PROG_QUERY_LAST_FIELD query.revision
4226468e2f64SAlexei Starovoitov 
bpf_prog_query(const union bpf_attr * attr,union bpf_attr __user * uattr)4227468e2f64SAlexei Starovoitov static int bpf_prog_query(const union bpf_attr *attr,
4228468e2f64SAlexei Starovoitov 			  union bpf_attr __user *uattr)
4229468e2f64SAlexei Starovoitov {
4230ed1ad5a7SAndrii Nakryiko 	if (!bpf_net_capable())
4231468e2f64SAlexei Starovoitov 		return -EPERM;
4232468e2f64SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_QUERY))
4233468e2f64SAlexei Starovoitov 		return -EINVAL;
4234468e2f64SAlexei Starovoitov 	if (attr->query.query_flags & ~BPF_F_QUERY_EFFECTIVE)
4235468e2f64SAlexei Starovoitov 		return -EINVAL;
4236468e2f64SAlexei Starovoitov 
4237468e2f64SAlexei Starovoitov 	switch (attr->query.attach_type) {
4238468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_INGRESS:
4239468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_EGRESS:
4240468e2f64SAlexei Starovoitov 	case BPF_CGROUP_INET_SOCK_CREATE:
4241f5836749SStanislav Fomichev 	case BPF_CGROUP_INET_SOCK_RELEASE:
42424fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET4_BIND:
42434fbac77dSAndrey Ignatov 	case BPF_CGROUP_INET6_BIND:
4244aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET4_POST_BIND:
4245aac3fc32SAndrey Ignatov 	case BPF_CGROUP_INET6_POST_BIND:
4246d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET4_CONNECT:
4247d74bad4eSAndrey Ignatov 	case BPF_CGROUP_INET6_CONNECT:
4248859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_CONNECT:
42491b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETPEERNAME:
42501b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETPEERNAME:
4251859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_GETPEERNAME:
42521b66d253SDaniel Borkmann 	case BPF_CGROUP_INET4_GETSOCKNAME:
42531b66d253SDaniel Borkmann 	case BPF_CGROUP_INET6_GETSOCKNAME:
4254859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_GETSOCKNAME:
42551cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP4_SENDMSG:
42561cedee13SAndrey Ignatov 	case BPF_CGROUP_UDP6_SENDMSG:
4257859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_SENDMSG:
4258983695faSDaniel Borkmann 	case BPF_CGROUP_UDP4_RECVMSG:
4259983695faSDaniel Borkmann 	case BPF_CGROUP_UDP6_RECVMSG:
4260859051ddSDaan De Meyer 	case BPF_CGROUP_UNIX_RECVMSG:
4261468e2f64SAlexei Starovoitov 	case BPF_CGROUP_SOCK_OPS:
4262ebc614f6SRoman Gushchin 	case BPF_CGROUP_DEVICE:
42637b146cebSAndrey Ignatov 	case BPF_CGROUP_SYSCTL:
42640d01da6aSStanislav Fomichev 	case BPF_CGROUP_GETSOCKOPT:
42650d01da6aSStanislav Fomichev 	case BPF_CGROUP_SETSOCKOPT:
4266b79c9fc9SStanislav Fomichev 	case BPF_LSM_CGROUP:
4267e28784e3SAndrii Nakryiko 		return cgroup_bpf_prog_query(attr, uattr);
4268f4364dcfSSean Young 	case BPF_LIRC_MODE2:
4269f4364dcfSSean Young 		return lirc_prog_query(attr, uattr);
4270118c8e9aSStanislav Fomichev 	case BPF_FLOW_DISSECTOR:
4271e9ddbb77SJakub Sitnicki 	case BPF_SK_LOOKUP:
4272a3fd7ceeSJakub Sitnicki 		return netns_bpf_prog_query(attr, uattr);
4273748cd572SDi Zhu 	case BPF_SK_SKB_STREAM_PARSER:
4274748cd572SDi Zhu 	case BPF_SK_SKB_STREAM_VERDICT:
4275748cd572SDi Zhu 	case BPF_SK_MSG_VERDICT:
4276748cd572SDi Zhu 	case BPF_SK_SKB_VERDICT:
4277748cd572SDi Zhu 		return sock_map_bpf_prog_query(attr, uattr);
4278e420bed0SDaniel Borkmann 	case BPF_TCX_INGRESS:
4279e420bed0SDaniel Borkmann 	case BPF_TCX_EGRESS:
4280e420bed0SDaniel Borkmann 		return tcx_prog_query(attr, uattr);
428135dfaad7SDaniel Borkmann 	case BPF_NETKIT_PRIMARY:
428235dfaad7SDaniel Borkmann 	case BPF_NETKIT_PEER:
428335dfaad7SDaniel Borkmann 		return netkit_prog_query(attr, uattr);
4284468e2f64SAlexei Starovoitov 	default:
4285468e2f64SAlexei Starovoitov 		return -EINVAL;
4286468e2f64SAlexei Starovoitov 	}
4287468e2f64SAlexei Starovoitov }
4288f4324551SDaniel Mack 
4289b530e9e1SToke Høiland-Jørgensen #define BPF_PROG_TEST_RUN_LAST_FIELD test.batch_size
42901cf1cae9SAlexei Starovoitov 
bpf_prog_test_run(const union bpf_attr * attr,union bpf_attr __user * uattr)42911cf1cae9SAlexei Starovoitov static int bpf_prog_test_run(const union bpf_attr *attr,
42921cf1cae9SAlexei Starovoitov 			     union bpf_attr __user *uattr)
42931cf1cae9SAlexei Starovoitov {
42941cf1cae9SAlexei Starovoitov 	struct bpf_prog *prog;
42951cf1cae9SAlexei Starovoitov 	int ret = -ENOTSUPP;
42961cf1cae9SAlexei Starovoitov 
42971cf1cae9SAlexei Starovoitov 	if (CHECK_ATTR(BPF_PROG_TEST_RUN))
42981cf1cae9SAlexei Starovoitov 		return -EINVAL;
42991cf1cae9SAlexei Starovoitov 
4300b0b9395dSStanislav Fomichev 	if ((attr->test.ctx_size_in && !attr->test.ctx_in) ||
4301b0b9395dSStanislav Fomichev 	    (!attr->test.ctx_size_in && attr->test.ctx_in))
4302b0b9395dSStanislav Fomichev 		return -EINVAL;
4303b0b9395dSStanislav Fomichev 
4304b0b9395dSStanislav Fomichev 	if ((attr->test.ctx_size_out && !attr->test.ctx_out) ||
4305b0b9395dSStanislav Fomichev 	    (!attr->test.ctx_size_out && attr->test.ctx_out))
4306b0b9395dSStanislav Fomichev 		return -EINVAL;
4307b0b9395dSStanislav Fomichev 
43081cf1cae9SAlexei Starovoitov 	prog = bpf_prog_get(attr->test.prog_fd);
43091cf1cae9SAlexei Starovoitov 	if (IS_ERR(prog))
43101cf1cae9SAlexei Starovoitov 		return PTR_ERR(prog);
43111cf1cae9SAlexei Starovoitov 
43121cf1cae9SAlexei Starovoitov 	if (prog->aux->ops->test_run)
43131cf1cae9SAlexei Starovoitov 		ret = prog->aux->ops->test_run(prog, attr, uattr);
43141cf1cae9SAlexei Starovoitov 
43151cf1cae9SAlexei Starovoitov 	bpf_prog_put(prog);
43161cf1cae9SAlexei Starovoitov 	return ret;
43171cf1cae9SAlexei Starovoitov }
43181cf1cae9SAlexei Starovoitov 
431934ad5580SMartin KaFai Lau #define BPF_OBJ_GET_NEXT_ID_LAST_FIELD next_id
432034ad5580SMartin KaFai Lau 
bpf_obj_get_next_id(const union bpf_attr * attr,union bpf_attr __user * uattr,struct idr * idr,spinlock_t * lock)432134ad5580SMartin KaFai Lau static int bpf_obj_get_next_id(const union bpf_attr *attr,
432234ad5580SMartin KaFai Lau 			       union bpf_attr __user *uattr,
432334ad5580SMartin KaFai Lau 			       struct idr *idr,
432434ad5580SMartin KaFai Lau 			       spinlock_t *lock)
432534ad5580SMartin KaFai Lau {
432634ad5580SMartin KaFai Lau 	u32 next_id = attr->start_id;
432734ad5580SMartin KaFai Lau 	int err = 0;
432834ad5580SMartin KaFai Lau 
432934ad5580SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_NEXT_ID) || next_id >= INT_MAX)
433034ad5580SMartin KaFai Lau 		return -EINVAL;
433134ad5580SMartin KaFai Lau 
433234ad5580SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
433334ad5580SMartin KaFai Lau 		return -EPERM;
433434ad5580SMartin KaFai Lau 
433534ad5580SMartin KaFai Lau 	next_id++;
433634ad5580SMartin KaFai Lau 	spin_lock_bh(lock);
433734ad5580SMartin KaFai Lau 	if (!idr_get_next(idr, &next_id))
433834ad5580SMartin KaFai Lau 		err = -ENOENT;
433934ad5580SMartin KaFai Lau 	spin_unlock_bh(lock);
434034ad5580SMartin KaFai Lau 
434134ad5580SMartin KaFai Lau 	if (!err)
434234ad5580SMartin KaFai Lau 		err = put_user(next_id, &uattr->next_id);
434334ad5580SMartin KaFai Lau 
434434ad5580SMartin KaFai Lau 	return err;
434534ad5580SMartin KaFai Lau }
434634ad5580SMartin KaFai Lau 
bpf_map_get_curr_or_next(u32 * id)43476086d29dSYonghong Song struct bpf_map *bpf_map_get_curr_or_next(u32 *id)
43486086d29dSYonghong Song {
43496086d29dSYonghong Song 	struct bpf_map *map;
43506086d29dSYonghong Song 
43516086d29dSYonghong Song 	spin_lock_bh(&map_idr_lock);
43526086d29dSYonghong Song again:
43536086d29dSYonghong Song 	map = idr_get_next(&map_idr, id);
43546086d29dSYonghong Song 	if (map) {
43556086d29dSYonghong Song 		map = __bpf_map_inc_not_zero(map, false);
43566086d29dSYonghong Song 		if (IS_ERR(map)) {
43576086d29dSYonghong Song 			(*id)++;
43586086d29dSYonghong Song 			goto again;
43596086d29dSYonghong Song 		}
43606086d29dSYonghong Song 	}
43616086d29dSYonghong Song 	spin_unlock_bh(&map_idr_lock);
43626086d29dSYonghong Song 
43636086d29dSYonghong Song 	return map;
43646086d29dSYonghong Song }
43656086d29dSYonghong Song 
bpf_prog_get_curr_or_next(u32 * id)4366a228a64fSAlexei Starovoitov struct bpf_prog *bpf_prog_get_curr_or_next(u32 *id)
4367a228a64fSAlexei Starovoitov {
4368a228a64fSAlexei Starovoitov 	struct bpf_prog *prog;
4369a228a64fSAlexei Starovoitov 
4370a228a64fSAlexei Starovoitov 	spin_lock_bh(&prog_idr_lock);
4371a228a64fSAlexei Starovoitov again:
4372a228a64fSAlexei Starovoitov 	prog = idr_get_next(&prog_idr, id);
4373a228a64fSAlexei Starovoitov 	if (prog) {
4374a228a64fSAlexei Starovoitov 		prog = bpf_prog_inc_not_zero(prog);
4375a228a64fSAlexei Starovoitov 		if (IS_ERR(prog)) {
4376a228a64fSAlexei Starovoitov 			(*id)++;
4377a228a64fSAlexei Starovoitov 			goto again;
4378a228a64fSAlexei Starovoitov 		}
4379a228a64fSAlexei Starovoitov 	}
4380a228a64fSAlexei Starovoitov 	spin_unlock_bh(&prog_idr_lock);
4381a228a64fSAlexei Starovoitov 
4382a228a64fSAlexei Starovoitov 	return prog;
4383a228a64fSAlexei Starovoitov }
4384a228a64fSAlexei Starovoitov 
4385b16d9aa4SMartin KaFai Lau #define BPF_PROG_GET_FD_BY_ID_LAST_FIELD prog_id
4386b16d9aa4SMartin KaFai Lau 
bpf_prog_by_id(u32 id)43877e6897f9SBjörn Töpel struct bpf_prog *bpf_prog_by_id(u32 id)
43887e6897f9SBjörn Töpel {
43897e6897f9SBjörn Töpel 	struct bpf_prog *prog;
43907e6897f9SBjörn Töpel 
43917e6897f9SBjörn Töpel 	if (!id)
43927e6897f9SBjörn Töpel 		return ERR_PTR(-ENOENT);
43937e6897f9SBjörn Töpel 
43947e6897f9SBjörn Töpel 	spin_lock_bh(&prog_idr_lock);
43957e6897f9SBjörn Töpel 	prog = idr_find(&prog_idr, id);
43967e6897f9SBjörn Töpel 	if (prog)
43977e6897f9SBjörn Töpel 		prog = bpf_prog_inc_not_zero(prog);
43987e6897f9SBjörn Töpel 	else
43997e6897f9SBjörn Töpel 		prog = ERR_PTR(-ENOENT);
44007e6897f9SBjörn Töpel 	spin_unlock_bh(&prog_idr_lock);
44017e6897f9SBjörn Töpel 	return prog;
44027e6897f9SBjörn Töpel }
44037e6897f9SBjörn Töpel 
bpf_prog_get_fd_by_id(const union bpf_attr * attr)4404b16d9aa4SMartin KaFai Lau static int bpf_prog_get_fd_by_id(const union bpf_attr *attr)
4405b16d9aa4SMartin KaFai Lau {
4406b16d9aa4SMartin KaFai Lau 	struct bpf_prog *prog;
4407b16d9aa4SMartin KaFai Lau 	u32 id = attr->prog_id;
4408b16d9aa4SMartin KaFai Lau 	int fd;
4409b16d9aa4SMartin KaFai Lau 
4410b16d9aa4SMartin KaFai Lau 	if (CHECK_ATTR(BPF_PROG_GET_FD_BY_ID))
4411b16d9aa4SMartin KaFai Lau 		return -EINVAL;
4412b16d9aa4SMartin KaFai Lau 
4413b16d9aa4SMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
4414b16d9aa4SMartin KaFai Lau 		return -EPERM;
4415b16d9aa4SMartin KaFai Lau 
44167e6897f9SBjörn Töpel 	prog = bpf_prog_by_id(id);
4417b16d9aa4SMartin KaFai Lau 	if (IS_ERR(prog))
4418b16d9aa4SMartin KaFai Lau 		return PTR_ERR(prog);
4419b16d9aa4SMartin KaFai Lau 
4420b16d9aa4SMartin KaFai Lau 	fd = bpf_prog_new_fd(prog);
4421b16d9aa4SMartin KaFai Lau 	if (fd < 0)
4422b16d9aa4SMartin KaFai Lau 		bpf_prog_put(prog);
4423b16d9aa4SMartin KaFai Lau 
4424b16d9aa4SMartin KaFai Lau 	return fd;
4425b16d9aa4SMartin KaFai Lau }
4426b16d9aa4SMartin KaFai Lau 
44276e71b04aSChenbo Feng #define BPF_MAP_GET_FD_BY_ID_LAST_FIELD open_flags
4428bd5f5f4eSMartin KaFai Lau 
bpf_map_get_fd_by_id(const union bpf_attr * attr)4429bd5f5f4eSMartin KaFai Lau static int bpf_map_get_fd_by_id(const union bpf_attr *attr)
4430bd5f5f4eSMartin KaFai Lau {
4431bd5f5f4eSMartin KaFai Lau 	struct bpf_map *map;
4432bd5f5f4eSMartin KaFai Lau 	u32 id = attr->map_id;
44336e71b04aSChenbo Feng 	int f_flags;
4434bd5f5f4eSMartin KaFai Lau 	int fd;
4435bd5f5f4eSMartin KaFai Lau 
44366e71b04aSChenbo Feng 	if (CHECK_ATTR(BPF_MAP_GET_FD_BY_ID) ||
44376e71b04aSChenbo Feng 	    attr->open_flags & ~BPF_OBJ_FLAG_MASK)
4438bd5f5f4eSMartin KaFai Lau 		return -EINVAL;
4439bd5f5f4eSMartin KaFai Lau 
4440bd5f5f4eSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
4441bd5f5f4eSMartin KaFai Lau 		return -EPERM;
4442bd5f5f4eSMartin KaFai Lau 
44436e71b04aSChenbo Feng 	f_flags = bpf_get_file_flag(attr->open_flags);
44446e71b04aSChenbo Feng 	if (f_flags < 0)
44456e71b04aSChenbo Feng 		return f_flags;
44466e71b04aSChenbo Feng 
4447bd5f5f4eSMartin KaFai Lau 	spin_lock_bh(&map_idr_lock);
4448bd5f5f4eSMartin KaFai Lau 	map = idr_find(&map_idr, id);
4449bd5f5f4eSMartin KaFai Lau 	if (map)
4450b0e4701cSStanislav Fomichev 		map = __bpf_map_inc_not_zero(map, true);
4451bd5f5f4eSMartin KaFai Lau 	else
4452bd5f5f4eSMartin KaFai Lau 		map = ERR_PTR(-ENOENT);
4453bd5f5f4eSMartin KaFai Lau 	spin_unlock_bh(&map_idr_lock);
4454bd5f5f4eSMartin KaFai Lau 
4455bd5f5f4eSMartin KaFai Lau 	if (IS_ERR(map))
4456bd5f5f4eSMartin KaFai Lau 		return PTR_ERR(map);
4457bd5f5f4eSMartin KaFai Lau 
44586e71b04aSChenbo Feng 	fd = bpf_map_new_fd(map, f_flags);
4459bd5f5f4eSMartin KaFai Lau 	if (fd < 0)
4460781e6282SPeng Sun 		bpf_map_put_with_uref(map);
4461bd5f5f4eSMartin KaFai Lau 
4462bd5f5f4eSMartin KaFai Lau 	return fd;
4463bd5f5f4eSMartin KaFai Lau }
4464bd5f5f4eSMartin KaFai Lau 
bpf_map_from_imm(const struct bpf_prog * prog,unsigned long addr,u32 * off,u32 * type)44657105e828SDaniel Borkmann static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog,
4466d8eca5bbSDaniel Borkmann 					      unsigned long addr, u32 *off,
4467d8eca5bbSDaniel Borkmann 					      u32 *type)
44687105e828SDaniel Borkmann {
4469d8eca5bbSDaniel Borkmann 	const struct bpf_map *map;
44707105e828SDaniel Borkmann 	int i;
44717105e828SDaniel Borkmann 
4472984fe94fSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
4473d8eca5bbSDaniel Borkmann 	for (i = 0, *off = 0; i < prog->aux->used_map_cnt; i++) {
4474d8eca5bbSDaniel Borkmann 		map = prog->aux->used_maps[i];
4475d8eca5bbSDaniel Borkmann 		if (map == (void *)addr) {
4476d8eca5bbSDaniel Borkmann 			*type = BPF_PSEUDO_MAP_FD;
4477984fe94fSYiFei Zhu 			goto out;
4478d8eca5bbSDaniel Borkmann 		}
4479d8eca5bbSDaniel Borkmann 		if (!map->ops->map_direct_value_meta)
4480d8eca5bbSDaniel Borkmann 			continue;
4481d8eca5bbSDaniel Borkmann 		if (!map->ops->map_direct_value_meta(map, addr, off)) {
4482d8eca5bbSDaniel Borkmann 			*type = BPF_PSEUDO_MAP_VALUE;
4483984fe94fSYiFei Zhu 			goto out;
4484d8eca5bbSDaniel Borkmann 		}
4485d8eca5bbSDaniel Borkmann 	}
4486984fe94fSYiFei Zhu 	map = NULL;
4487d8eca5bbSDaniel Borkmann 
4488984fe94fSYiFei Zhu out:
4489984fe94fSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
4490984fe94fSYiFei Zhu 	return map;
44917105e828SDaniel Borkmann }
44927105e828SDaniel Borkmann 
bpf_insn_prepare_dump(const struct bpf_prog * prog,const struct cred * f_cred)449363960260SKees Cook static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog,
449463960260SKees Cook 					      const struct cred *f_cred)
44957105e828SDaniel Borkmann {
44967105e828SDaniel Borkmann 	const struct bpf_map *map;
44977105e828SDaniel Borkmann 	struct bpf_insn *insns;
4498d8eca5bbSDaniel Borkmann 	u32 off, type;
44997105e828SDaniel Borkmann 	u64 imm;
450029fcb05bSAndrii Nakryiko 	u8 code;
45017105e828SDaniel Borkmann 	int i;
45027105e828SDaniel Borkmann 
45037105e828SDaniel Borkmann 	insns = kmemdup(prog->insnsi, bpf_prog_insn_size(prog),
45047105e828SDaniel Borkmann 			GFP_USER);
45057105e828SDaniel Borkmann 	if (!insns)
45067105e828SDaniel Borkmann 		return insns;
45077105e828SDaniel Borkmann 
45087105e828SDaniel Borkmann 	for (i = 0; i < prog->len; i++) {
450929fcb05bSAndrii Nakryiko 		code = insns[i].code;
451029fcb05bSAndrii Nakryiko 
451129fcb05bSAndrii Nakryiko 		if (code == (BPF_JMP | BPF_TAIL_CALL)) {
45127105e828SDaniel Borkmann 			insns[i].code = BPF_JMP | BPF_CALL;
45137105e828SDaniel Borkmann 			insns[i].imm = BPF_FUNC_tail_call;
45147105e828SDaniel Borkmann 			/* fall-through */
45157105e828SDaniel Borkmann 		}
451629fcb05bSAndrii Nakryiko 		if (code == (BPF_JMP | BPF_CALL) ||
451729fcb05bSAndrii Nakryiko 		    code == (BPF_JMP | BPF_CALL_ARGS)) {
451829fcb05bSAndrii Nakryiko 			if (code == (BPF_JMP | BPF_CALL_ARGS))
45197105e828SDaniel Borkmann 				insns[i].code = BPF_JMP | BPF_CALL;
452063960260SKees Cook 			if (!bpf_dump_raw_ok(f_cred))
45217105e828SDaniel Borkmann 				insns[i].imm = 0;
45227105e828SDaniel Borkmann 			continue;
45237105e828SDaniel Borkmann 		}
452429fcb05bSAndrii Nakryiko 		if (BPF_CLASS(code) == BPF_LDX && BPF_MODE(code) == BPF_PROBE_MEM) {
452529fcb05bSAndrii Nakryiko 			insns[i].code = BPF_LDX | BPF_SIZE(code) | BPF_MEM;
452629fcb05bSAndrii Nakryiko 			continue;
452729fcb05bSAndrii Nakryiko 		}
45287105e828SDaniel Borkmann 
45296082b6c3SAlexei Starovoitov 		if ((BPF_CLASS(code) == BPF_LDX || BPF_CLASS(code) == BPF_STX ||
45306082b6c3SAlexei Starovoitov 		     BPF_CLASS(code) == BPF_ST) && BPF_MODE(code) == BPF_PROBE_MEM32) {
45316082b6c3SAlexei Starovoitov 			insns[i].code = BPF_CLASS(code) | BPF_SIZE(code) | BPF_MEM;
45326082b6c3SAlexei Starovoitov 			continue;
45336082b6c3SAlexei Starovoitov 		}
45346082b6c3SAlexei Starovoitov 
453529fcb05bSAndrii Nakryiko 		if (code != (BPF_LD | BPF_IMM | BPF_DW))
45367105e828SDaniel Borkmann 			continue;
45377105e828SDaniel Borkmann 
45387105e828SDaniel Borkmann 		imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm;
4539d8eca5bbSDaniel Borkmann 		map = bpf_map_from_imm(prog, imm, &off, &type);
45407105e828SDaniel Borkmann 		if (map) {
4541d8eca5bbSDaniel Borkmann 			insns[i].src_reg = type;
45427105e828SDaniel Borkmann 			insns[i].imm = map->id;
4543d8eca5bbSDaniel Borkmann 			insns[i + 1].imm = off;
45447105e828SDaniel Borkmann 			continue;
45457105e828SDaniel Borkmann 		}
45467105e828SDaniel Borkmann 	}
45477105e828SDaniel Borkmann 
45487105e828SDaniel Borkmann 	return insns;
45497105e828SDaniel Borkmann }
45507105e828SDaniel Borkmann 
set_info_rec_size(struct bpf_prog_info * info)4551c454a46bSMartin KaFai Lau static int set_info_rec_size(struct bpf_prog_info *info)
4552c454a46bSMartin KaFai Lau {
4553c454a46bSMartin KaFai Lau 	/*
4554c454a46bSMartin KaFai Lau 	 * Ensure info.*_rec_size is the same as kernel expected size
4555c454a46bSMartin KaFai Lau 	 *
4556c454a46bSMartin KaFai Lau 	 * or
4557c454a46bSMartin KaFai Lau 	 *
4558c454a46bSMartin KaFai Lau 	 * Only allow zero *_rec_size if both _rec_size and _cnt are
4559c454a46bSMartin KaFai Lau 	 * zero.  In this case, the kernel will set the expected
4560c454a46bSMartin KaFai Lau 	 * _rec_size back to the info.
4561c454a46bSMartin KaFai Lau 	 */
4562c454a46bSMartin KaFai Lau 
456311d8b82dSYonghong Song 	if ((info->nr_func_info || info->func_info_rec_size) &&
4564c454a46bSMartin KaFai Lau 	    info->func_info_rec_size != sizeof(struct bpf_func_info))
4565c454a46bSMartin KaFai Lau 		return -EINVAL;
4566c454a46bSMartin KaFai Lau 
456711d8b82dSYonghong Song 	if ((info->nr_line_info || info->line_info_rec_size) &&
4568c454a46bSMartin KaFai Lau 	    info->line_info_rec_size != sizeof(struct bpf_line_info))
4569c454a46bSMartin KaFai Lau 		return -EINVAL;
4570c454a46bSMartin KaFai Lau 
457111d8b82dSYonghong Song 	if ((info->nr_jited_line_info || info->jited_line_info_rec_size) &&
4572c454a46bSMartin KaFai Lau 	    info->jited_line_info_rec_size != sizeof(__u64))
4573c454a46bSMartin KaFai Lau 		return -EINVAL;
4574c454a46bSMartin KaFai Lau 
4575c454a46bSMartin KaFai Lau 	info->func_info_rec_size = sizeof(struct bpf_func_info);
4576c454a46bSMartin KaFai Lau 	info->line_info_rec_size = sizeof(struct bpf_line_info);
4577c454a46bSMartin KaFai Lau 	info->jited_line_info_rec_size = sizeof(__u64);
4578c454a46bSMartin KaFai Lau 
4579c454a46bSMartin KaFai Lau 	return 0;
4580c454a46bSMartin KaFai Lau }
4581c454a46bSMartin KaFai Lau 
bpf_prog_get_info_by_fd(struct file * file,struct bpf_prog * prog,const union bpf_attr * attr,union bpf_attr __user * uattr)458263960260SKees Cook static int bpf_prog_get_info_by_fd(struct file *file,
458363960260SKees Cook 				   struct bpf_prog *prog,
45841e270976SMartin KaFai Lau 				   const union bpf_attr *attr,
45851e270976SMartin KaFai Lau 				   union bpf_attr __user *uattr)
45861e270976SMartin KaFai Lau {
45871e270976SMartin KaFai Lau 	struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info);
45886644aabbSStanislav Fomichev 	struct btf *attach_btf = bpf_prog_get_target_btf(prog);
45895c6f2588SGreg Kroah-Hartman 	struct bpf_prog_info info;
45901e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
459161a0abaeSEric Dumazet 	struct bpf_prog_kstats stats;
45921e270976SMartin KaFai Lau 	char __user *uinsns;
45931e270976SMartin KaFai Lau 	u32 ulen;
45941e270976SMartin KaFai Lau 	int err;
45951e270976SMartin KaFai Lau 
4596af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len);
45971e270976SMartin KaFai Lau 	if (err)
45981e270976SMartin KaFai Lau 		return err;
45991e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
46001e270976SMartin KaFai Lau 
46015c6f2588SGreg Kroah-Hartman 	memset(&info, 0, sizeof(info));
46021e270976SMartin KaFai Lau 	if (copy_from_user(&info, uinfo, info_len))
460389b09689SDaniel Borkmann 		return -EFAULT;
46041e270976SMartin KaFai Lau 
46051e270976SMartin KaFai Lau 	info.type = prog->type;
46061e270976SMartin KaFai Lau 	info.id = prog->aux->id;
4607cb4d2b3fSMartin KaFai Lau 	info.load_time = prog->aux->load_time;
4608cb4d2b3fSMartin KaFai Lau 	info.created_by_uid = from_kuid_munged(current_user_ns(),
4609cb4d2b3fSMartin KaFai Lau 					       prog->aux->user->uid);
4610b85fab0eSJiri Olsa 	info.gpl_compatible = prog->gpl_compatible;
46111e270976SMartin KaFai Lau 
46121e270976SMartin KaFai Lau 	memcpy(info.tag, prog->tag, sizeof(prog->tag));
4613cb4d2b3fSMartin KaFai Lau 	memcpy(info.name, prog->aux->name, sizeof(prog->aux->name));
4614cb4d2b3fSMartin KaFai Lau 
4615984fe94fSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
4616cb4d2b3fSMartin KaFai Lau 	ulen = info.nr_map_ids;
4617cb4d2b3fSMartin KaFai Lau 	info.nr_map_ids = prog->aux->used_map_cnt;
4618cb4d2b3fSMartin KaFai Lau 	ulen = min_t(u32, info.nr_map_ids, ulen);
4619cb4d2b3fSMartin KaFai Lau 	if (ulen) {
4620721e08daSMartin KaFai Lau 		u32 __user *user_map_ids = u64_to_user_ptr(info.map_ids);
4621cb4d2b3fSMartin KaFai Lau 		u32 i;
4622cb4d2b3fSMartin KaFai Lau 
4623cb4d2b3fSMartin KaFai Lau 		for (i = 0; i < ulen; i++)
4624cb4d2b3fSMartin KaFai Lau 			if (put_user(prog->aux->used_maps[i]->id,
4625984fe94fSYiFei Zhu 				     &user_map_ids[i])) {
4626984fe94fSYiFei Zhu 				mutex_unlock(&prog->aux->used_maps_mutex);
4627cb4d2b3fSMartin KaFai Lau 				return -EFAULT;
4628cb4d2b3fSMartin KaFai Lau 			}
4629984fe94fSYiFei Zhu 	}
4630984fe94fSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
46311e270976SMartin KaFai Lau 
4632c454a46bSMartin KaFai Lau 	err = set_info_rec_size(&info);
4633c454a46bSMartin KaFai Lau 	if (err)
4634c454a46bSMartin KaFai Lau 		return err;
46357337224fSMartin KaFai Lau 
46365f8f8b93SAlexei Starovoitov 	bpf_prog_get_stats(prog, &stats);
46375f8f8b93SAlexei Starovoitov 	info.run_time_ns = stats.nsecs;
46385f8f8b93SAlexei Starovoitov 	info.run_cnt = stats.cnt;
46399ed9e9baSAlexei Starovoitov 	info.recursion_misses = stats.misses;
46405f8f8b93SAlexei Starovoitov 
4641aba64c7dSDave Marchevsky 	info.verified_insns = prog->aux->verified_insns;
4642aba64c7dSDave Marchevsky 
46432c78ee89SAlexei Starovoitov 	if (!bpf_capable()) {
46441e270976SMartin KaFai Lau 		info.jited_prog_len = 0;
46451e270976SMartin KaFai Lau 		info.xlated_prog_len = 0;
4646dbecd738SSandipan Das 		info.nr_jited_ksyms = 0;
464728c2fae7SDaniel Borkmann 		info.nr_jited_func_lens = 0;
464811d8b82dSYonghong Song 		info.nr_func_info = 0;
464911d8b82dSYonghong Song 		info.nr_line_info = 0;
465011d8b82dSYonghong Song 		info.nr_jited_line_info = 0;
46511e270976SMartin KaFai Lau 		goto done;
46521e270976SMartin KaFai Lau 	}
46531e270976SMartin KaFai Lau 
46541e270976SMartin KaFai Lau 	ulen = info.xlated_prog_len;
46559975a54bSDaniel Borkmann 	info.xlated_prog_len = bpf_prog_insn_size(prog);
46561e270976SMartin KaFai Lau 	if (info.xlated_prog_len && ulen) {
46577105e828SDaniel Borkmann 		struct bpf_insn *insns_sanitized;
46587105e828SDaniel Borkmann 		bool fault;
46597105e828SDaniel Borkmann 
466063960260SKees Cook 		if (prog->blinded && !bpf_dump_raw_ok(file->f_cred)) {
46617105e828SDaniel Borkmann 			info.xlated_prog_insns = 0;
46627105e828SDaniel Borkmann 			goto done;
46637105e828SDaniel Borkmann 		}
466463960260SKees Cook 		insns_sanitized = bpf_insn_prepare_dump(prog, file->f_cred);
46657105e828SDaniel Borkmann 		if (!insns_sanitized)
46667105e828SDaniel Borkmann 			return -ENOMEM;
46671e270976SMartin KaFai Lau 		uinsns = u64_to_user_ptr(info.xlated_prog_insns);
46681e270976SMartin KaFai Lau 		ulen = min_t(u32, info.xlated_prog_len, ulen);
46697105e828SDaniel Borkmann 		fault = copy_to_user(uinsns, insns_sanitized, ulen);
46707105e828SDaniel Borkmann 		kfree(insns_sanitized);
46717105e828SDaniel Borkmann 		if (fault)
46721e270976SMartin KaFai Lau 			return -EFAULT;
46731e270976SMartin KaFai Lau 	}
46741e270976SMartin KaFai Lau 
46759d03ebc7SStanislav Fomichev 	if (bpf_prog_is_offloaded(prog->aux)) {
4676675fc275SJakub Kicinski 		err = bpf_prog_offload_info_fill(&info, prog);
4677675fc275SJakub Kicinski 		if (err)
4678675fc275SJakub Kicinski 			return err;
4679fcfb126dSJiong Wang 		goto done;
4680fcfb126dSJiong Wang 	}
4681fcfb126dSJiong Wang 
4682fcfb126dSJiong Wang 	/* NOTE: the following code is supposed to be skipped for offload.
4683fcfb126dSJiong Wang 	 * bpf_prog_offload_info_fill() is the place to fill similar fields
4684fcfb126dSJiong Wang 	 * for offload.
4685fcfb126dSJiong Wang 	 */
4686fcfb126dSJiong Wang 	ulen = info.jited_prog_len;
46874d56a76eSSandipan Das 	if (prog->aux->func_cnt) {
46884d56a76eSSandipan Das 		u32 i;
46894d56a76eSSandipan Das 
46904d56a76eSSandipan Das 		info.jited_prog_len = 0;
46914d56a76eSSandipan Das 		for (i = 0; i < prog->aux->func_cnt; i++)
46924d56a76eSSandipan Das 			info.jited_prog_len += prog->aux->func[i]->jited_len;
46934d56a76eSSandipan Das 	} else {
4694fcfb126dSJiong Wang 		info.jited_prog_len = prog->jited_len;
46954d56a76eSSandipan Das 	}
46964d56a76eSSandipan Das 
4697fcfb126dSJiong Wang 	if (info.jited_prog_len && ulen) {
469863960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
4699fcfb126dSJiong Wang 			uinsns = u64_to_user_ptr(info.jited_prog_insns);
4700fcfb126dSJiong Wang 			ulen = min_t(u32, info.jited_prog_len, ulen);
47014d56a76eSSandipan Das 
47024d56a76eSSandipan Das 			/* for multi-function programs, copy the JITed
47034d56a76eSSandipan Das 			 * instructions for all the functions
47044d56a76eSSandipan Das 			 */
47054d56a76eSSandipan Das 			if (prog->aux->func_cnt) {
47064d56a76eSSandipan Das 				u32 len, free, i;
47074d56a76eSSandipan Das 				u8 *img;
47084d56a76eSSandipan Das 
47094d56a76eSSandipan Das 				free = ulen;
47104d56a76eSSandipan Das 				for (i = 0; i < prog->aux->func_cnt; i++) {
47114d56a76eSSandipan Das 					len = prog->aux->func[i]->jited_len;
47124d56a76eSSandipan Das 					len = min_t(u32, len, free);
47134d56a76eSSandipan Das 					img = (u8 *) prog->aux->func[i]->bpf_func;
47144d56a76eSSandipan Das 					if (copy_to_user(uinsns, img, len))
47154d56a76eSSandipan Das 						return -EFAULT;
47164d56a76eSSandipan Das 					uinsns += len;
47174d56a76eSSandipan Das 					free -= len;
47184d56a76eSSandipan Das 					if (!free)
47194d56a76eSSandipan Das 						break;
47204d56a76eSSandipan Das 				}
47214d56a76eSSandipan Das 			} else {
4722fcfb126dSJiong Wang 				if (copy_to_user(uinsns, prog->bpf_func, ulen))
4723fcfb126dSJiong Wang 					return -EFAULT;
47244d56a76eSSandipan Das 			}
4725fcfb126dSJiong Wang 		} else {
4726fcfb126dSJiong Wang 			info.jited_prog_insns = 0;
4727fcfb126dSJiong Wang 		}
4728675fc275SJakub Kicinski 	}
4729675fc275SJakub Kicinski 
4730dbecd738SSandipan Das 	ulen = info.nr_jited_ksyms;
4731ff1889fcSSong Liu 	info.nr_jited_ksyms = prog->aux->func_cnt ? : 1;
47327a5725ddSSong Liu 	if (ulen) {
473363960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
4734ff1889fcSSong Liu 			unsigned long ksym_addr;
4735dbecd738SSandipan Das 			u64 __user *user_ksyms;
4736dbecd738SSandipan Das 			u32 i;
4737dbecd738SSandipan Das 
4738dbecd738SSandipan Das 			/* copy the address of the kernel symbol
4739dbecd738SSandipan Das 			 * corresponding to each function
4740dbecd738SSandipan Das 			 */
4741dbecd738SSandipan Das 			ulen = min_t(u32, info.nr_jited_ksyms, ulen);
4742dbecd738SSandipan Das 			user_ksyms = u64_to_user_ptr(info.jited_ksyms);
4743ff1889fcSSong Liu 			if (prog->aux->func_cnt) {
4744dbecd738SSandipan Das 				for (i = 0; i < ulen; i++) {
4745ff1889fcSSong Liu 					ksym_addr = (unsigned long)
4746ff1889fcSSong Liu 						prog->aux->func[i]->bpf_func;
4747ff1889fcSSong Liu 					if (put_user((u64) ksym_addr,
4748ff1889fcSSong Liu 						     &user_ksyms[i]))
4749ff1889fcSSong Liu 						return -EFAULT;
4750ff1889fcSSong Liu 				}
4751ff1889fcSSong Liu 			} else {
4752ff1889fcSSong Liu 				ksym_addr = (unsigned long) prog->bpf_func;
4753ff1889fcSSong Liu 				if (put_user((u64) ksym_addr, &user_ksyms[0]))
4754dbecd738SSandipan Das 					return -EFAULT;
4755dbecd738SSandipan Das 			}
4756dbecd738SSandipan Das 		} else {
4757dbecd738SSandipan Das 			info.jited_ksyms = 0;
4758dbecd738SSandipan Das 		}
4759dbecd738SSandipan Das 	}
4760dbecd738SSandipan Das 
4761815581c1SSandipan Das 	ulen = info.nr_jited_func_lens;
4762ff1889fcSSong Liu 	info.nr_jited_func_lens = prog->aux->func_cnt ? : 1;
47637a5725ddSSong Liu 	if (ulen) {
476463960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
4765815581c1SSandipan Das 			u32 __user *user_lens;
4766815581c1SSandipan Das 			u32 func_len, i;
4767815581c1SSandipan Das 
4768815581c1SSandipan Das 			/* copy the JITed image lengths for each function */
4769815581c1SSandipan Das 			ulen = min_t(u32, info.nr_jited_func_lens, ulen);
4770815581c1SSandipan Das 			user_lens = u64_to_user_ptr(info.jited_func_lens);
4771ff1889fcSSong Liu 			if (prog->aux->func_cnt) {
4772815581c1SSandipan Das 				for (i = 0; i < ulen; i++) {
4773ff1889fcSSong Liu 					func_len =
4774ff1889fcSSong Liu 						prog->aux->func[i]->jited_len;
4775815581c1SSandipan Das 					if (put_user(func_len, &user_lens[i]))
4776815581c1SSandipan Das 						return -EFAULT;
4777815581c1SSandipan Das 				}
4778815581c1SSandipan Das 			} else {
4779ff1889fcSSong Liu 				func_len = prog->jited_len;
4780ff1889fcSSong Liu 				if (put_user(func_len, &user_lens[0]))
4781ff1889fcSSong Liu 					return -EFAULT;
4782ff1889fcSSong Liu 			}
4783ff1889fcSSong Liu 		} else {
4784815581c1SSandipan Das 			info.jited_func_lens = 0;
4785815581c1SSandipan Das 		}
4786815581c1SSandipan Das 	}
4787815581c1SSandipan Das 
47887337224fSMartin KaFai Lau 	if (prog->aux->btf)
478922dc4a0fSAndrii Nakryiko 		info.btf_id = btf_obj_id(prog->aux->btf);
4790b79c9fc9SStanislav Fomichev 	info.attach_btf_id = prog->aux->attach_btf_id;
47916644aabbSStanislav Fomichev 	if (attach_btf)
47926644aabbSStanislav Fomichev 		info.attach_btf_obj_id = btf_obj_id(attach_btf);
4793838e9690SYonghong Song 
479411d8b82dSYonghong Song 	ulen = info.nr_func_info;
479511d8b82dSYonghong Song 	info.nr_func_info = prog->aux->func_info_cnt;
479611d8b82dSYonghong Song 	if (info.nr_func_info && ulen) {
4797838e9690SYonghong Song 		char __user *user_finfo;
4798838e9690SYonghong Song 
4799838e9690SYonghong Song 		user_finfo = u64_to_user_ptr(info.func_info);
480011d8b82dSYonghong Song 		ulen = min_t(u32, info.nr_func_info, ulen);
4801ba64e7d8SYonghong Song 		if (copy_to_user(user_finfo, prog->aux->func_info,
48027337224fSMartin KaFai Lau 				 info.func_info_rec_size * ulen))
4803838e9690SYonghong Song 			return -EFAULT;
4804838e9690SYonghong Song 	}
4805838e9690SYonghong Song 
480611d8b82dSYonghong Song 	ulen = info.nr_line_info;
480711d8b82dSYonghong Song 	info.nr_line_info = prog->aux->nr_linfo;
480811d8b82dSYonghong Song 	if (info.nr_line_info && ulen) {
4809c454a46bSMartin KaFai Lau 		__u8 __user *user_linfo;
4810c454a46bSMartin KaFai Lau 
4811c454a46bSMartin KaFai Lau 		user_linfo = u64_to_user_ptr(info.line_info);
481211d8b82dSYonghong Song 		ulen = min_t(u32, info.nr_line_info, ulen);
4813c454a46bSMartin KaFai Lau 		if (copy_to_user(user_linfo, prog->aux->linfo,
4814c454a46bSMartin KaFai Lau 				 info.line_info_rec_size * ulen))
4815c454a46bSMartin KaFai Lau 			return -EFAULT;
4816c454a46bSMartin KaFai Lau 	}
4817c454a46bSMartin KaFai Lau 
481811d8b82dSYonghong Song 	ulen = info.nr_jited_line_info;
4819c454a46bSMartin KaFai Lau 	if (prog->aux->jited_linfo)
482011d8b82dSYonghong Song 		info.nr_jited_line_info = prog->aux->nr_linfo;
4821c454a46bSMartin KaFai Lau 	else
482211d8b82dSYonghong Song 		info.nr_jited_line_info = 0;
482311d8b82dSYonghong Song 	if (info.nr_jited_line_info && ulen) {
482463960260SKees Cook 		if (bpf_dump_raw_ok(file->f_cred)) {
48252cd00852SPu Lehui 			unsigned long line_addr;
4826c454a46bSMartin KaFai Lau 			__u64 __user *user_linfo;
4827c454a46bSMartin KaFai Lau 			u32 i;
4828c454a46bSMartin KaFai Lau 
4829c454a46bSMartin KaFai Lau 			user_linfo = u64_to_user_ptr(info.jited_line_info);
483011d8b82dSYonghong Song 			ulen = min_t(u32, info.nr_jited_line_info, ulen);
4831c454a46bSMartin KaFai Lau 			for (i = 0; i < ulen; i++) {
48322cd00852SPu Lehui 				line_addr = (unsigned long)prog->aux->jited_linfo[i];
48332cd00852SPu Lehui 				if (put_user((__u64)line_addr, &user_linfo[i]))
4834c454a46bSMartin KaFai Lau 					return -EFAULT;
4835c454a46bSMartin KaFai Lau 			}
4836c454a46bSMartin KaFai Lau 		} else {
4837c454a46bSMartin KaFai Lau 			info.jited_line_info = 0;
4838c454a46bSMartin KaFai Lau 		}
4839c454a46bSMartin KaFai Lau 	}
4840c454a46bSMartin KaFai Lau 
4841c872bdb3SSong Liu 	ulen = info.nr_prog_tags;
4842c872bdb3SSong Liu 	info.nr_prog_tags = prog->aux->func_cnt ? : 1;
4843c872bdb3SSong Liu 	if (ulen) {
4844c872bdb3SSong Liu 		__u8 __user (*user_prog_tags)[BPF_TAG_SIZE];
4845c872bdb3SSong Liu 		u32 i;
4846c872bdb3SSong Liu 
4847c872bdb3SSong Liu 		user_prog_tags = u64_to_user_ptr(info.prog_tags);
4848c872bdb3SSong Liu 		ulen = min_t(u32, info.nr_prog_tags, ulen);
4849c872bdb3SSong Liu 		if (prog->aux->func_cnt) {
4850c872bdb3SSong Liu 			for (i = 0; i < ulen; i++) {
4851c872bdb3SSong Liu 				if (copy_to_user(user_prog_tags[i],
4852c872bdb3SSong Liu 						 prog->aux->func[i]->tag,
4853c872bdb3SSong Liu 						 BPF_TAG_SIZE))
4854c872bdb3SSong Liu 					return -EFAULT;
4855c872bdb3SSong Liu 			}
4856c872bdb3SSong Liu 		} else {
4857c872bdb3SSong Liu 			if (copy_to_user(user_prog_tags[0],
4858c872bdb3SSong Liu 					 prog->tag, BPF_TAG_SIZE))
4859c872bdb3SSong Liu 				return -EFAULT;
4860c872bdb3SSong Liu 		}
4861c872bdb3SSong Liu 	}
4862c872bdb3SSong Liu 
48631e270976SMartin KaFai Lau done:
48641e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
48651e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
48661e270976SMartin KaFai Lau 		return -EFAULT;
48671e270976SMartin KaFai Lau 
48681e270976SMartin KaFai Lau 	return 0;
48691e270976SMartin KaFai Lau }
48701e270976SMartin KaFai Lau 
bpf_map_get_info_by_fd(struct file * file,struct bpf_map * map,const union bpf_attr * attr,union bpf_attr __user * uattr)487163960260SKees Cook static int bpf_map_get_info_by_fd(struct file *file,
487263960260SKees Cook 				  struct bpf_map *map,
48731e270976SMartin KaFai Lau 				  const union bpf_attr *attr,
48741e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
48751e270976SMartin KaFai Lau {
48761e270976SMartin KaFai Lau 	struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info);
48775c6f2588SGreg Kroah-Hartman 	struct bpf_map_info info;
48781e270976SMartin KaFai Lau 	u32 info_len = attr->info.info_len;
48791e270976SMartin KaFai Lau 	int err;
48801e270976SMartin KaFai Lau 
4881af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len);
48821e270976SMartin KaFai Lau 	if (err)
48831e270976SMartin KaFai Lau 		return err;
48841e270976SMartin KaFai Lau 	info_len = min_t(u32, sizeof(info), info_len);
48851e270976SMartin KaFai Lau 
48865c6f2588SGreg Kroah-Hartman 	memset(&info, 0, sizeof(info));
48871e270976SMartin KaFai Lau 	info.type = map->map_type;
48881e270976SMartin KaFai Lau 	info.id = map->id;
48891e270976SMartin KaFai Lau 	info.key_size = map->key_size;
48901e270976SMartin KaFai Lau 	info.value_size = map->value_size;
48911e270976SMartin KaFai Lau 	info.max_entries = map->max_entries;
48921e270976SMartin KaFai Lau 	info.map_flags = map->map_flags;
48939330986cSJoanne Koong 	info.map_extra = map->map_extra;
4894ad5b177bSMartin KaFai Lau 	memcpy(info.name, map->name, sizeof(map->name));
48951e270976SMartin KaFai Lau 
489678958fcaSMartin KaFai Lau 	if (map->btf) {
489722dc4a0fSAndrii Nakryiko 		info.btf_id = btf_obj_id(map->btf);
48989b2cf328SMartin KaFai Lau 		info.btf_key_type_id = map->btf_key_type_id;
48999b2cf328SMartin KaFai Lau 		info.btf_value_type_id = map->btf_value_type_id;
490078958fcaSMartin KaFai Lau 	}
490185d33df3SMartin KaFai Lau 	info.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id;
49021338b933SKui-Feng Lee 	if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS)
49031338b933SKui-Feng Lee 		bpf_map_struct_ops_info_fill(&info, map);
490478958fcaSMartin KaFai Lau 
49059d03ebc7SStanislav Fomichev 	if (bpf_map_is_offloaded(map)) {
490652775b33SJakub Kicinski 		err = bpf_map_offload_info_fill(&info, map);
490752775b33SJakub Kicinski 		if (err)
490852775b33SJakub Kicinski 			return err;
490952775b33SJakub Kicinski 	}
491052775b33SJakub Kicinski 
49111e270976SMartin KaFai Lau 	if (copy_to_user(uinfo, &info, info_len) ||
49121e270976SMartin KaFai Lau 	    put_user(info_len, &uattr->info.info_len))
49131e270976SMartin KaFai Lau 		return -EFAULT;
49141e270976SMartin KaFai Lau 
49151e270976SMartin KaFai Lau 	return 0;
49161e270976SMartin KaFai Lau }
49171e270976SMartin KaFai Lau 
bpf_btf_get_info_by_fd(struct file * file,struct btf * btf,const union bpf_attr * attr,union bpf_attr __user * uattr)491863960260SKees Cook static int bpf_btf_get_info_by_fd(struct file *file,
491963960260SKees Cook 				  struct btf *btf,
492062dab84cSMartin KaFai Lau 				  const union bpf_attr *attr,
492162dab84cSMartin KaFai Lau 				  union bpf_attr __user *uattr)
492262dab84cSMartin KaFai Lau {
492362dab84cSMartin KaFai Lau 	struct bpf_btf_info __user *uinfo = u64_to_user_ptr(attr->info.info);
492462dab84cSMartin KaFai Lau 	u32 info_len = attr->info.info_len;
492562dab84cSMartin KaFai Lau 	int err;
492662dab84cSMartin KaFai Lau 
4927af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(*uinfo), info_len);
492862dab84cSMartin KaFai Lau 	if (err)
492962dab84cSMartin KaFai Lau 		return err;
493062dab84cSMartin KaFai Lau 
493162dab84cSMartin KaFai Lau 	return btf_get_info_by_fd(btf, attr, uattr);
493262dab84cSMartin KaFai Lau }
493362dab84cSMartin KaFai Lau 
bpf_link_get_info_by_fd(struct file * file,struct bpf_link * link,const union bpf_attr * attr,union bpf_attr __user * uattr)493463960260SKees Cook static int bpf_link_get_info_by_fd(struct file *file,
493563960260SKees Cook 				  struct bpf_link *link,
4936f2e10bffSAndrii Nakryiko 				  const union bpf_attr *attr,
4937f2e10bffSAndrii Nakryiko 				  union bpf_attr __user *uattr)
4938f2e10bffSAndrii Nakryiko {
4939f2e10bffSAndrii Nakryiko 	struct bpf_link_info __user *uinfo = u64_to_user_ptr(attr->info.info);
4940f2e10bffSAndrii Nakryiko 	struct bpf_link_info info;
4941f2e10bffSAndrii Nakryiko 	u32 info_len = attr->info.info_len;
4942f2e10bffSAndrii Nakryiko 	int err;
4943f2e10bffSAndrii Nakryiko 
4944af2ac3e1SAlexei Starovoitov 	err = bpf_check_uarg_tail_zero(USER_BPFPTR(uinfo), sizeof(info), info_len);
4945f2e10bffSAndrii Nakryiko 	if (err)
4946f2e10bffSAndrii Nakryiko 		return err;
4947f2e10bffSAndrii Nakryiko 	info_len = min_t(u32, sizeof(info), info_len);
4948f2e10bffSAndrii Nakryiko 
4949f2e10bffSAndrii Nakryiko 	memset(&info, 0, sizeof(info));
4950f2e10bffSAndrii Nakryiko 	if (copy_from_user(&info, uinfo, info_len))
4951f2e10bffSAndrii Nakryiko 		return -EFAULT;
4952f2e10bffSAndrii Nakryiko 
4953f2e10bffSAndrii Nakryiko 	info.type = link->type;
4954f2e10bffSAndrii Nakryiko 	info.id = link->id;
495568b04864SKui-Feng Lee 	if (link->prog)
4956f2e10bffSAndrii Nakryiko 		info.prog_id = link->prog->aux->id;
4957f2e10bffSAndrii Nakryiko 
4958f2e10bffSAndrii Nakryiko 	if (link->ops->fill_link_info) {
4959f2e10bffSAndrii Nakryiko 		err = link->ops->fill_link_info(link, &info);
4960f2e10bffSAndrii Nakryiko 		if (err)
4961f2e10bffSAndrii Nakryiko 			return err;
4962f2e10bffSAndrii Nakryiko 	}
4963f2e10bffSAndrii Nakryiko 
4964f2e10bffSAndrii Nakryiko 	if (copy_to_user(uinfo, &info, info_len) ||
4965f2e10bffSAndrii Nakryiko 	    put_user(info_len, &uattr->info.info_len))
4966f2e10bffSAndrii Nakryiko 		return -EFAULT;
4967f2e10bffSAndrii Nakryiko 
4968f2e10bffSAndrii Nakryiko 	return 0;
4969f2e10bffSAndrii Nakryiko }
4970f2e10bffSAndrii Nakryiko 
4971f2e10bffSAndrii Nakryiko 
49721e270976SMartin KaFai Lau #define BPF_OBJ_GET_INFO_BY_FD_LAST_FIELD info.info
49731e270976SMartin KaFai Lau 
bpf_obj_get_info_by_fd(const union bpf_attr * attr,union bpf_attr __user * uattr)49741e270976SMartin KaFai Lau static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
49751e270976SMartin KaFai Lau 				  union bpf_attr __user *uattr)
49761e270976SMartin KaFai Lau {
49771e270976SMartin KaFai Lau 	int ufd = attr->info.bpf_fd;
49781e270976SMartin KaFai Lau 	struct fd f;
49791e270976SMartin KaFai Lau 	int err;
49801e270976SMartin KaFai Lau 
49811e270976SMartin KaFai Lau 	if (CHECK_ATTR(BPF_OBJ_GET_INFO_BY_FD))
49821e270976SMartin KaFai Lau 		return -EINVAL;
49831e270976SMartin KaFai Lau 
49841e270976SMartin KaFai Lau 	f = fdget(ufd);
49851e270976SMartin KaFai Lau 	if (!f.file)
49861e270976SMartin KaFai Lau 		return -EBADFD;
49871e270976SMartin KaFai Lau 
49881e270976SMartin KaFai Lau 	if (f.file->f_op == &bpf_prog_fops)
498963960260SKees Cook 		err = bpf_prog_get_info_by_fd(f.file, f.file->private_data, attr,
49901e270976SMartin KaFai Lau 					      uattr);
49911e270976SMartin KaFai Lau 	else if (f.file->f_op == &bpf_map_fops)
499263960260SKees Cook 		err = bpf_map_get_info_by_fd(f.file, f.file->private_data, attr,
49931e270976SMartin KaFai Lau 					     uattr);
499460197cfbSMartin KaFai Lau 	else if (f.file->f_op == &btf_fops)
499563960260SKees Cook 		err = bpf_btf_get_info_by_fd(f.file, f.file->private_data, attr, uattr);
49961adddc97SKui-Feng Lee 	else if (f.file->f_op == &bpf_link_fops || f.file->f_op == &bpf_link_fops_poll)
499763960260SKees Cook 		err = bpf_link_get_info_by_fd(f.file, f.file->private_data,
4998f2e10bffSAndrii Nakryiko 					      attr, uattr);
49991e270976SMartin KaFai Lau 	else
50001e270976SMartin KaFai Lau 		err = -EINVAL;
50011e270976SMartin KaFai Lau 
50021e270976SMartin KaFai Lau 	fdput(f);
50031e270976SMartin KaFai Lau 	return err;
50041e270976SMartin KaFai Lau }
50051e270976SMartin KaFai Lau 
50069ea7c4bfSAndrii Nakryiko #define BPF_BTF_LOAD_LAST_FIELD btf_token_fd
5007f56a653cSMartin KaFai Lau 
bpf_btf_load(const union bpf_attr * attr,bpfptr_t uattr,__u32 uattr_size)500847a71c1fSAndrii Nakryiko static int bpf_btf_load(const union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_size)
5009f56a653cSMartin KaFai Lau {
50109ea7c4bfSAndrii Nakryiko 	struct bpf_token *token = NULL;
50119ea7c4bfSAndrii Nakryiko 
5012f56a653cSMartin KaFai Lau 	if (CHECK_ATTR(BPF_BTF_LOAD))
5013f56a653cSMartin KaFai Lau 		return -EINVAL;
5014f56a653cSMartin KaFai Lau 
50159ea7c4bfSAndrii Nakryiko 	if (attr->btf_flags & ~BPF_F_TOKEN_FD)
50169ea7c4bfSAndrii Nakryiko 		return -EINVAL;
50179ea7c4bfSAndrii Nakryiko 
50189ea7c4bfSAndrii Nakryiko 	if (attr->btf_flags & BPF_F_TOKEN_FD) {
50199ea7c4bfSAndrii Nakryiko 		token = bpf_token_get_from_fd(attr->btf_token_fd);
50209ea7c4bfSAndrii Nakryiko 		if (IS_ERR(token))
50219ea7c4bfSAndrii Nakryiko 			return PTR_ERR(token);
50229ea7c4bfSAndrii Nakryiko 		if (!bpf_token_allow_cmd(token, BPF_BTF_LOAD)) {
50239ea7c4bfSAndrii Nakryiko 			bpf_token_put(token);
50249ea7c4bfSAndrii Nakryiko 			token = NULL;
50259ea7c4bfSAndrii Nakryiko 		}
50269ea7c4bfSAndrii Nakryiko 	}
50279ea7c4bfSAndrii Nakryiko 
50289ea7c4bfSAndrii Nakryiko 	if (!bpf_token_capable(token, CAP_BPF)) {
50299ea7c4bfSAndrii Nakryiko 		bpf_token_put(token);
5030f56a653cSMartin KaFai Lau 		return -EPERM;
50319ea7c4bfSAndrii Nakryiko 	}
50329ea7c4bfSAndrii Nakryiko 
50339ea7c4bfSAndrii Nakryiko 	bpf_token_put(token);
5034f56a653cSMartin KaFai Lau 
503547a71c1fSAndrii Nakryiko 	return btf_new_fd(attr, uattr, uattr_size);
5036f56a653cSMartin KaFai Lau }
5037f56a653cSMartin KaFai Lau 
503878958fcaSMartin KaFai Lau #define BPF_BTF_GET_FD_BY_ID_LAST_FIELD btf_id
503978958fcaSMartin KaFai Lau 
bpf_btf_get_fd_by_id(const union bpf_attr * attr)504078958fcaSMartin KaFai Lau static int bpf_btf_get_fd_by_id(const union bpf_attr *attr)
504178958fcaSMartin KaFai Lau {
504278958fcaSMartin KaFai Lau 	if (CHECK_ATTR(BPF_BTF_GET_FD_BY_ID))
504378958fcaSMartin KaFai Lau 		return -EINVAL;
504478958fcaSMartin KaFai Lau 
504578958fcaSMartin KaFai Lau 	if (!capable(CAP_SYS_ADMIN))
504678958fcaSMartin KaFai Lau 		return -EPERM;
504778958fcaSMartin KaFai Lau 
504878958fcaSMartin KaFai Lau 	return btf_get_fd_by_id(attr->btf_id);
504978958fcaSMartin KaFai Lau }
505078958fcaSMartin KaFai Lau 
bpf_task_fd_query_copy(const union bpf_attr * attr,union bpf_attr __user * uattr,u32 prog_id,u32 fd_type,const char * buf,u64 probe_offset,u64 probe_addr)505141bdc4b4SYonghong Song static int bpf_task_fd_query_copy(const union bpf_attr *attr,
505241bdc4b4SYonghong Song 				    union bpf_attr __user *uattr,
505341bdc4b4SYonghong Song 				    u32 prog_id, u32 fd_type,
505441bdc4b4SYonghong Song 				    const char *buf, u64 probe_offset,
505541bdc4b4SYonghong Song 				    u64 probe_addr)
505641bdc4b4SYonghong Song {
505741bdc4b4SYonghong Song 	char __user *ubuf = u64_to_user_ptr(attr->task_fd_query.buf);
505841bdc4b4SYonghong Song 	u32 len = buf ? strlen(buf) : 0, input_len;
505941bdc4b4SYonghong Song 	int err = 0;
506041bdc4b4SYonghong Song 
506141bdc4b4SYonghong Song 	if (put_user(len, &uattr->task_fd_query.buf_len))
506241bdc4b4SYonghong Song 		return -EFAULT;
506341bdc4b4SYonghong Song 	input_len = attr->task_fd_query.buf_len;
506441bdc4b4SYonghong Song 	if (input_len && ubuf) {
506541bdc4b4SYonghong Song 		if (!len) {
506641bdc4b4SYonghong Song 			/* nothing to copy, just make ubuf NULL terminated */
506741bdc4b4SYonghong Song 			char zero = '\0';
506841bdc4b4SYonghong Song 
506941bdc4b4SYonghong Song 			if (put_user(zero, ubuf))
507041bdc4b4SYonghong Song 				return -EFAULT;
507141bdc4b4SYonghong Song 		} else if (input_len >= len + 1) {
507241bdc4b4SYonghong Song 			/* ubuf can hold the string with NULL terminator */
507341bdc4b4SYonghong Song 			if (copy_to_user(ubuf, buf, len + 1))
507441bdc4b4SYonghong Song 				return -EFAULT;
507541bdc4b4SYonghong Song 		} else {
507641bdc4b4SYonghong Song 			/* ubuf cannot hold the string with NULL terminator,
507741bdc4b4SYonghong Song 			 * do a partial copy with NULL terminator.
507841bdc4b4SYonghong Song 			 */
507941bdc4b4SYonghong Song 			char zero = '\0';
508041bdc4b4SYonghong Song 
508141bdc4b4SYonghong Song 			err = -ENOSPC;
508241bdc4b4SYonghong Song 			if (copy_to_user(ubuf, buf, input_len - 1))
508341bdc4b4SYonghong Song 				return -EFAULT;
508441bdc4b4SYonghong Song 			if (put_user(zero, ubuf + input_len - 1))
508541bdc4b4SYonghong Song 				return -EFAULT;
508641bdc4b4SYonghong Song 		}
508741bdc4b4SYonghong Song 	}
508841bdc4b4SYonghong Song 
508941bdc4b4SYonghong Song 	if (put_user(prog_id, &uattr->task_fd_query.prog_id) ||
509041bdc4b4SYonghong Song 	    put_user(fd_type, &uattr->task_fd_query.fd_type) ||
509141bdc4b4SYonghong Song 	    put_user(probe_offset, &uattr->task_fd_query.probe_offset) ||
509241bdc4b4SYonghong Song 	    put_user(probe_addr, &uattr->task_fd_query.probe_addr))
509341bdc4b4SYonghong Song 		return -EFAULT;
509441bdc4b4SYonghong Song 
509541bdc4b4SYonghong Song 	return err;
509641bdc4b4SYonghong Song }
509741bdc4b4SYonghong Song 
509841bdc4b4SYonghong Song #define BPF_TASK_FD_QUERY_LAST_FIELD task_fd_query.probe_addr
509941bdc4b4SYonghong Song 
bpf_task_fd_query(const union bpf_attr * attr,union bpf_attr __user * uattr)510041bdc4b4SYonghong Song static int bpf_task_fd_query(const union bpf_attr *attr,
510141bdc4b4SYonghong Song 			     union bpf_attr __user *uattr)
510241bdc4b4SYonghong Song {
510341bdc4b4SYonghong Song 	pid_t pid = attr->task_fd_query.pid;
510441bdc4b4SYonghong Song 	u32 fd = attr->task_fd_query.fd;
510541bdc4b4SYonghong Song 	const struct perf_event *event;
510641bdc4b4SYonghong Song 	struct task_struct *task;
510741bdc4b4SYonghong Song 	struct file *file;
510841bdc4b4SYonghong Song 	int err;
510941bdc4b4SYonghong Song 
511041bdc4b4SYonghong Song 	if (CHECK_ATTR(BPF_TASK_FD_QUERY))
511141bdc4b4SYonghong Song 		return -EINVAL;
511241bdc4b4SYonghong Song 
511341bdc4b4SYonghong Song 	if (!capable(CAP_SYS_ADMIN))
511441bdc4b4SYonghong Song 		return -EPERM;
511541bdc4b4SYonghong Song 
511641bdc4b4SYonghong Song 	if (attr->task_fd_query.flags != 0)
511741bdc4b4SYonghong Song 		return -EINVAL;
511841bdc4b4SYonghong Song 
511983c10cc3SLee Jones 	rcu_read_lock();
512041bdc4b4SYonghong Song 	task = get_pid_task(find_vpid(pid), PIDTYPE_PID);
512183c10cc3SLee Jones 	rcu_read_unlock();
512241bdc4b4SYonghong Song 	if (!task)
512341bdc4b4SYonghong Song 		return -ENOENT;
512441bdc4b4SYonghong Song 
512541bdc4b4SYonghong Song 	err = 0;
5126b48845afSEric W. Biederman 	file = fget_task(task, fd);
5127b48845afSEric W. Biederman 	put_task_struct(task);
512841bdc4b4SYonghong Song 	if (!file)
5129b48845afSEric W. Biederman 		return -EBADF;
513041bdc4b4SYonghong Song 
51311adddc97SKui-Feng Lee 	if (file->f_op == &bpf_link_fops || file->f_op == &bpf_link_fops_poll) {
513270ed506cSAndrii Nakryiko 		struct bpf_link *link = file->private_data;
513370ed506cSAndrii Nakryiko 
5134a3b80e10SAndrii Nakryiko 		if (link->ops == &bpf_raw_tp_link_lops) {
513570ed506cSAndrii Nakryiko 			struct bpf_raw_tp_link *raw_tp =
513670ed506cSAndrii Nakryiko 				container_of(link, struct bpf_raw_tp_link, link);
513741bdc4b4SYonghong Song 			struct bpf_raw_event_map *btp = raw_tp->btp;
513841bdc4b4SYonghong Song 
513941bdc4b4SYonghong Song 			err = bpf_task_fd_query_copy(attr, uattr,
514070ed506cSAndrii Nakryiko 						     raw_tp->link.prog->aux->id,
514141bdc4b4SYonghong Song 						     BPF_FD_TYPE_RAW_TRACEPOINT,
514241bdc4b4SYonghong Song 						     btp->tp->name, 0, 0);
514341bdc4b4SYonghong Song 			goto put_file;
514441bdc4b4SYonghong Song 		}
514570ed506cSAndrii Nakryiko 		goto out_not_supp;
514670ed506cSAndrii Nakryiko 	}
514741bdc4b4SYonghong Song 
514841bdc4b4SYonghong Song 	event = perf_get_event(file);
514941bdc4b4SYonghong Song 	if (!IS_ERR(event)) {
515041bdc4b4SYonghong Song 		u64 probe_offset, probe_addr;
515141bdc4b4SYonghong Song 		u32 prog_id, fd_type;
515241bdc4b4SYonghong Song 		const char *buf;
515341bdc4b4SYonghong Song 
515441bdc4b4SYonghong Song 		err = bpf_get_perf_event_info(event, &prog_id, &fd_type,
515541bdc4b4SYonghong Song 					      &buf, &probe_offset,
51563acf8aceSJiri Olsa 					      &probe_addr, NULL);
515741bdc4b4SYonghong Song 		if (!err)
515841bdc4b4SYonghong Song 			err = bpf_task_fd_query_copy(attr, uattr, prog_id,
515941bdc4b4SYonghong Song 						     fd_type, buf,
516041bdc4b4SYonghong Song 						     probe_offset,
516141bdc4b4SYonghong Song 						     probe_addr);
516241bdc4b4SYonghong Song 		goto put_file;
516341bdc4b4SYonghong Song 	}
516441bdc4b4SYonghong Song 
516570ed506cSAndrii Nakryiko out_not_supp:
516641bdc4b4SYonghong Song 	err = -ENOTSUPP;
516741bdc4b4SYonghong Song put_file:
516841bdc4b4SYonghong Song 	fput(file);
516941bdc4b4SYonghong Song 	return err;
517041bdc4b4SYonghong Song }
517141bdc4b4SYonghong Song 
5172cb4d03abSBrian Vazquez #define BPF_MAP_BATCH_LAST_FIELD batch.flags
5173cb4d03abSBrian Vazquez 
51743af43ba4SHou Tao #define BPF_DO_BATCH(fn, ...)			\
5175cb4d03abSBrian Vazquez 	do {					\
5176cb4d03abSBrian Vazquez 		if (!fn) {			\
5177cb4d03abSBrian Vazquez 			err = -ENOTSUPP;	\
5178cb4d03abSBrian Vazquez 			goto err_put;		\
5179cb4d03abSBrian Vazquez 		}				\
51803af43ba4SHou Tao 		err = fn(__VA_ARGS__);		\
5181cb4d03abSBrian Vazquez 	} while (0)
5182cb4d03abSBrian Vazquez 
bpf_map_do_batch(const union bpf_attr * attr,union bpf_attr __user * uattr,int cmd)5183cb4d03abSBrian Vazquez static int bpf_map_do_batch(const union bpf_attr *attr,
5184cb4d03abSBrian Vazquez 			    union bpf_attr __user *uattr,
5185cb4d03abSBrian Vazquez 			    int cmd)
5186cb4d03abSBrian Vazquez {
5187353050beSDaniel Borkmann 	bool has_read  = cmd == BPF_MAP_LOOKUP_BATCH ||
5188353050beSDaniel Borkmann 			 cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH;
5189353050beSDaniel Borkmann 	bool has_write = cmd != BPF_MAP_LOOKUP_BATCH;
5190cb4d03abSBrian Vazquez 	struct bpf_map *map;
5191cb4d03abSBrian Vazquez 	int err, ufd;
5192cb4d03abSBrian Vazquez 	struct fd f;
5193cb4d03abSBrian Vazquez 
5194cb4d03abSBrian Vazquez 	if (CHECK_ATTR(BPF_MAP_BATCH))
5195cb4d03abSBrian Vazquez 		return -EINVAL;
5196cb4d03abSBrian Vazquez 
5197cb4d03abSBrian Vazquez 	ufd = attr->batch.map_fd;
5198cb4d03abSBrian Vazquez 	f = fdget(ufd);
5199cb4d03abSBrian Vazquez 	map = __bpf_map_get(f);
5200cb4d03abSBrian Vazquez 	if (IS_ERR(map))
5201cb4d03abSBrian Vazquez 		return PTR_ERR(map);
5202353050beSDaniel Borkmann 	if (has_write)
5203353050beSDaniel Borkmann 		bpf_map_write_active_inc(map);
5204353050beSDaniel Borkmann 	if (has_read && !(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
5205cb4d03abSBrian Vazquez 		err = -EPERM;
5206cb4d03abSBrian Vazquez 		goto err_put;
5207cb4d03abSBrian Vazquez 	}
5208353050beSDaniel Borkmann 	if (has_write && !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
5209cb4d03abSBrian Vazquez 		err = -EPERM;
5210cb4d03abSBrian Vazquez 		goto err_put;
5211cb4d03abSBrian Vazquez 	}
5212cb4d03abSBrian Vazquez 
5213cb4d03abSBrian Vazquez 	if (cmd == BPF_MAP_LOOKUP_BATCH)
52143af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_lookup_batch, map, attr, uattr);
521505799638SYonghong Song 	else if (cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH)
52163af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_lookup_and_delete_batch, map, attr, uattr);
5217aa2e93b8SBrian Vazquez 	else if (cmd == BPF_MAP_UPDATE_BATCH)
52183af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_update_batch, map, f.file, attr, uattr);
5219aa2e93b8SBrian Vazquez 	else
52203af43ba4SHou Tao 		BPF_DO_BATCH(map->ops->map_delete_batch, map, attr, uattr);
5221cb4d03abSBrian Vazquez err_put:
522201277258SHou Tao 	if (has_write) {
522301277258SHou Tao 		maybe_wait_bpf_programs(map);
5224353050beSDaniel Borkmann 		bpf_map_write_active_dec(map);
522501277258SHou Tao 	}
5226cb4d03abSBrian Vazquez 	fdput(f);
5227cb4d03abSBrian Vazquez 	return err;
5228cb4d03abSBrian Vazquez }
5229cb4d03abSBrian Vazquez 
5230b733eeadSJiri Olsa #define BPF_LINK_CREATE_LAST_FIELD link_create.uprobe_multi.pid
link_create(union bpf_attr * attr,bpfptr_t uattr)5231af2ac3e1SAlexei Starovoitov static int link_create(union bpf_attr *attr, bpfptr_t uattr)
5232af6eea57SAndrii Nakryiko {
5233af6eea57SAndrii Nakryiko 	struct bpf_prog *prog;
5234af6eea57SAndrii Nakryiko 	int ret;
5235af6eea57SAndrii Nakryiko 
5236af6eea57SAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_CREATE))
5237af6eea57SAndrii Nakryiko 		return -EINVAL;
5238af6eea57SAndrii Nakryiko 
523968b04864SKui-Feng Lee 	if (attr->link_create.attach_type == BPF_STRUCT_OPS)
524068b04864SKui-Feng Lee 		return bpf_struct_ops_link_create(attr);
524168b04864SKui-Feng Lee 
52424a1e7c0cSToke Høiland-Jørgensen 	prog = bpf_prog_get(attr->link_create.prog_fd);
5243af6eea57SAndrii Nakryiko 	if (IS_ERR(prog))
5244af6eea57SAndrii Nakryiko 		return PTR_ERR(prog);
5245af6eea57SAndrii Nakryiko 
5246af6eea57SAndrii Nakryiko 	ret = bpf_prog_attach_check_attach_type(prog,
5247af6eea57SAndrii Nakryiko 						attr->link_create.attach_type);
5248af6eea57SAndrii Nakryiko 	if (ret)
52494a1e7c0cSToke Høiland-Jørgensen 		goto out;
52504a1e7c0cSToke Høiland-Jørgensen 
5251b89fbfbbSAndrii Nakryiko 	switch (prog->type) {
5252af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SKB:
5253af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK:
5254af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
5255af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_SOCK_OPS:
5256af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_DEVICE:
5257af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SYSCTL:
5258af6eea57SAndrii Nakryiko 	case BPF_PROG_TYPE_CGROUP_SOCKOPT:
5259af6eea57SAndrii Nakryiko 		ret = cgroup_bpf_link_attach(attr, prog);
5260af6eea57SAndrii Nakryiko 		break;
5261df86ca0dSAndrii Nakryiko 	case BPF_PROG_TYPE_EXT:
5262df86ca0dSAndrii Nakryiko 		ret = bpf_tracing_prog_attach(prog,
5263df86ca0dSAndrii Nakryiko 					      attr->link_create.target_fd,
52642fcc8241SKui-Feng Lee 					      attr->link_create.target_btf_id,
52652fcc8241SKui-Feng Lee 					      attr->link_create.tracing.cookie);
5266df86ca0dSAndrii Nakryiko 		break;
5267df86ca0dSAndrii Nakryiko 	case BPF_PROG_TYPE_LSM:
5268de4e05caSYonghong Song 	case BPF_PROG_TYPE_TRACING:
5269df86ca0dSAndrii Nakryiko 		if (attr->link_create.attach_type != prog->expected_attach_type) {
5270df86ca0dSAndrii Nakryiko 			ret = -EINVAL;
5271df86ca0dSAndrii Nakryiko 			goto out;
5272df86ca0dSAndrii Nakryiko 		}
5273df86ca0dSAndrii Nakryiko 		if (prog->expected_attach_type == BPF_TRACE_RAW_TP)
527468ca5d4eSAndrii Nakryiko 			ret = bpf_raw_tp_link_attach(prog, NULL, attr->link_create.tracing.cookie);
5275df86ca0dSAndrii Nakryiko 		else if (prog->expected_attach_type == BPF_TRACE_ITER)
5276df86ca0dSAndrii Nakryiko 			ret = bpf_iter_link_attach(attr, uattr, prog);
527769fd337aSStanislav Fomichev 		else if (prog->expected_attach_type == BPF_LSM_CGROUP)
527869fd337aSStanislav Fomichev 			ret = cgroup_bpf_link_attach(attr, prog);
5279df86ca0dSAndrii Nakryiko 		else
5280df86ca0dSAndrii Nakryiko 			ret = bpf_tracing_prog_attach(prog,
5281df86ca0dSAndrii Nakryiko 						      attr->link_create.target_fd,
52822fcc8241SKui-Feng Lee 						      attr->link_create.target_btf_id,
52832fcc8241SKui-Feng Lee 						      attr->link_create.tracing.cookie);
5284de4e05caSYonghong Song 		break;
52857f045a49SJakub Sitnicki 	case BPF_PROG_TYPE_FLOW_DISSECTOR:
5286e9ddbb77SJakub Sitnicki 	case BPF_PROG_TYPE_SK_LOOKUP:
52877f045a49SJakub Sitnicki 		ret = netns_bpf_link_create(attr, prog);
52887f045a49SJakub Sitnicki 		break;
5289699c23f0SYonghong Song 	case BPF_PROG_TYPE_SK_MSG:
5290699c23f0SYonghong Song 	case BPF_PROG_TYPE_SK_SKB:
5291699c23f0SYonghong Song 		ret = sock_map_link_create(attr, prog);
5292699c23f0SYonghong Song 		break;
5293310ad797SAndrii Nakryiko #ifdef CONFIG_NET
5294aa8d3a71SAndrii Nakryiko 	case BPF_PROG_TYPE_XDP:
5295aa8d3a71SAndrii Nakryiko 		ret = bpf_xdp_link_attach(attr, prog);
5296aa8d3a71SAndrii Nakryiko 		break;
5297e420bed0SDaniel Borkmann 	case BPF_PROG_TYPE_SCHED_CLS:
529835dfaad7SDaniel Borkmann 		if (attr->link_create.attach_type == BPF_TCX_INGRESS ||
529935dfaad7SDaniel Borkmann 		    attr->link_create.attach_type == BPF_TCX_EGRESS)
5300e420bed0SDaniel Borkmann 			ret = tcx_link_attach(attr, prog);
530135dfaad7SDaniel Borkmann 		else
530235dfaad7SDaniel Borkmann 			ret = netkit_link_attach(attr, prog);
5303e420bed0SDaniel Borkmann 		break;
530484601d6eSFlorian Westphal 	case BPF_PROG_TYPE_NETFILTER:
530584601d6eSFlorian Westphal 		ret = bpf_nf_link_attach(attr, prog);
530684601d6eSFlorian Westphal 		break;
5307310ad797SAndrii Nakryiko #endif
5308b89fbfbbSAndrii Nakryiko 	case BPF_PROG_TYPE_PERF_EVENT:
5309b89fbfbbSAndrii Nakryiko 	case BPF_PROG_TYPE_TRACEPOINT:
5310b89fbfbbSAndrii Nakryiko 		ret = bpf_perf_link_attach(attr, prog);
5311b89fbfbbSAndrii Nakryiko 		break;
53120dcac272SJiri Olsa 	case BPF_PROG_TYPE_KPROBE:
53130dcac272SJiri Olsa 		if (attr->link_create.attach_type == BPF_PERF_EVENT)
53140dcac272SJiri Olsa 			ret = bpf_perf_link_attach(attr, prog);
5315535a3692SJiri Olsa 		else if (attr->link_create.attach_type == BPF_TRACE_KPROBE_MULTI ||
5316535a3692SJiri Olsa 			 attr->link_create.attach_type == BPF_TRACE_KPROBE_SESSION)
53170dcac272SJiri Olsa 			ret = bpf_kprobe_multi_link_attach(attr, prog);
531889ae89f5SJiri Olsa 		else if (attr->link_create.attach_type == BPF_TRACE_UPROBE_MULTI)
531989ae89f5SJiri Olsa 			ret = bpf_uprobe_multi_link_attach(attr, prog);
53200dcac272SJiri Olsa 		break;
5321af6eea57SAndrii Nakryiko 	default:
5322af6eea57SAndrii Nakryiko 		ret = -EINVAL;
5323af6eea57SAndrii Nakryiko 	}
5324af6eea57SAndrii Nakryiko 
53254a1e7c0cSToke Høiland-Jørgensen out:
5326af6eea57SAndrii Nakryiko 	if (ret < 0)
5327af6eea57SAndrii Nakryiko 		bpf_prog_put(prog);
5328af6eea57SAndrii Nakryiko 	return ret;
5329af6eea57SAndrii Nakryiko }
5330af6eea57SAndrii Nakryiko 
link_update_map(struct bpf_link * link,union bpf_attr * attr)5331aef56f2eSKui-Feng Lee static int link_update_map(struct bpf_link *link, union bpf_attr *attr)
5332aef56f2eSKui-Feng Lee {
5333aef56f2eSKui-Feng Lee 	struct bpf_map *new_map, *old_map = NULL;
5334aef56f2eSKui-Feng Lee 	int ret;
5335aef56f2eSKui-Feng Lee 
5336aef56f2eSKui-Feng Lee 	new_map = bpf_map_get(attr->link_update.new_map_fd);
5337aef56f2eSKui-Feng Lee 	if (IS_ERR(new_map))
533855fbae05SMartin KaFai Lau 		return PTR_ERR(new_map);
5339aef56f2eSKui-Feng Lee 
5340aef56f2eSKui-Feng Lee 	if (attr->link_update.flags & BPF_F_REPLACE) {
5341aef56f2eSKui-Feng Lee 		old_map = bpf_map_get(attr->link_update.old_map_fd);
5342aef56f2eSKui-Feng Lee 		if (IS_ERR(old_map)) {
534355fbae05SMartin KaFai Lau 			ret = PTR_ERR(old_map);
5344aef56f2eSKui-Feng Lee 			goto out_put;
5345aef56f2eSKui-Feng Lee 		}
5346aef56f2eSKui-Feng Lee 	} else if (attr->link_update.old_map_fd) {
5347aef56f2eSKui-Feng Lee 		ret = -EINVAL;
5348aef56f2eSKui-Feng Lee 		goto out_put;
5349aef56f2eSKui-Feng Lee 	}
5350aef56f2eSKui-Feng Lee 
5351aef56f2eSKui-Feng Lee 	ret = link->ops->update_map(link, new_map, old_map);
5352aef56f2eSKui-Feng Lee 
5353aef56f2eSKui-Feng Lee 	if (old_map)
5354aef56f2eSKui-Feng Lee 		bpf_map_put(old_map);
5355aef56f2eSKui-Feng Lee out_put:
5356aef56f2eSKui-Feng Lee 	bpf_map_put(new_map);
5357aef56f2eSKui-Feng Lee 	return ret;
5358aef56f2eSKui-Feng Lee }
5359aef56f2eSKui-Feng Lee 
53600c991ebcSAndrii Nakryiko #define BPF_LINK_UPDATE_LAST_FIELD link_update.old_prog_fd
53610c991ebcSAndrii Nakryiko 
link_update(union bpf_attr * attr)53620c991ebcSAndrii Nakryiko static int link_update(union bpf_attr *attr)
53630c991ebcSAndrii Nakryiko {
53640c991ebcSAndrii Nakryiko 	struct bpf_prog *old_prog = NULL, *new_prog;
53650c991ebcSAndrii Nakryiko 	struct bpf_link *link;
53660c991ebcSAndrii Nakryiko 	u32 flags;
53670c991ebcSAndrii Nakryiko 	int ret;
53680c991ebcSAndrii Nakryiko 
53690c991ebcSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_UPDATE))
53700c991ebcSAndrii Nakryiko 		return -EINVAL;
53710c991ebcSAndrii Nakryiko 
53720c991ebcSAndrii Nakryiko 	flags = attr->link_update.flags;
53730c991ebcSAndrii Nakryiko 	if (flags & ~BPF_F_REPLACE)
53740c991ebcSAndrii Nakryiko 		return -EINVAL;
53750c991ebcSAndrii Nakryiko 
53760c991ebcSAndrii Nakryiko 	link = bpf_link_get_from_fd(attr->link_update.link_fd);
53770c991ebcSAndrii Nakryiko 	if (IS_ERR(link))
53780c991ebcSAndrii Nakryiko 		return PTR_ERR(link);
53790c991ebcSAndrii Nakryiko 
5380aef56f2eSKui-Feng Lee 	if (link->ops->update_map) {
5381aef56f2eSKui-Feng Lee 		ret = link_update_map(link, attr);
5382aef56f2eSKui-Feng Lee 		goto out_put_link;
5383aef56f2eSKui-Feng Lee 	}
5384aef56f2eSKui-Feng Lee 
53850c991ebcSAndrii Nakryiko 	new_prog = bpf_prog_get(attr->link_update.new_prog_fd);
53864adb7a4aSAndrii Nakryiko 	if (IS_ERR(new_prog)) {
53874adb7a4aSAndrii Nakryiko 		ret = PTR_ERR(new_prog);
53884adb7a4aSAndrii Nakryiko 		goto out_put_link;
53894adb7a4aSAndrii Nakryiko 	}
53900c991ebcSAndrii Nakryiko 
53910c991ebcSAndrii Nakryiko 	if (flags & BPF_F_REPLACE) {
53920c991ebcSAndrii Nakryiko 		old_prog = bpf_prog_get(attr->link_update.old_prog_fd);
53930c991ebcSAndrii Nakryiko 		if (IS_ERR(old_prog)) {
53940c991ebcSAndrii Nakryiko 			ret = PTR_ERR(old_prog);
53950c991ebcSAndrii Nakryiko 			old_prog = NULL;
53960c991ebcSAndrii Nakryiko 			goto out_put_progs;
53970c991ebcSAndrii Nakryiko 		}
53984adb7a4aSAndrii Nakryiko 	} else if (attr->link_update.old_prog_fd) {
53994adb7a4aSAndrii Nakryiko 		ret = -EINVAL;
54004adb7a4aSAndrii Nakryiko 		goto out_put_progs;
54010c991ebcSAndrii Nakryiko 	}
54020c991ebcSAndrii Nakryiko 
5403f9d04127SAndrii Nakryiko 	if (link->ops->update_prog)
5404f9d04127SAndrii Nakryiko 		ret = link->ops->update_prog(link, new_prog, old_prog);
5405f9d04127SAndrii Nakryiko 	else
54060c991ebcSAndrii Nakryiko 		ret = -EINVAL;
54070c991ebcSAndrii Nakryiko 
54080c991ebcSAndrii Nakryiko out_put_progs:
54090c991ebcSAndrii Nakryiko 	if (old_prog)
54100c991ebcSAndrii Nakryiko 		bpf_prog_put(old_prog);
54110c991ebcSAndrii Nakryiko 	if (ret)
54120c991ebcSAndrii Nakryiko 		bpf_prog_put(new_prog);
54134adb7a4aSAndrii Nakryiko out_put_link:
5414ab5d47bdSSebastian Andrzej Siewior 	bpf_link_put_direct(link);
54150c991ebcSAndrii Nakryiko 	return ret;
54160c991ebcSAndrii Nakryiko }
54170c991ebcSAndrii Nakryiko 
541873b11c2aSAndrii Nakryiko #define BPF_LINK_DETACH_LAST_FIELD link_detach.link_fd
541973b11c2aSAndrii Nakryiko 
link_detach(union bpf_attr * attr)542073b11c2aSAndrii Nakryiko static int link_detach(union bpf_attr *attr)
542173b11c2aSAndrii Nakryiko {
542273b11c2aSAndrii Nakryiko 	struct bpf_link *link;
542373b11c2aSAndrii Nakryiko 	int ret;
542473b11c2aSAndrii Nakryiko 
542573b11c2aSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_DETACH))
542673b11c2aSAndrii Nakryiko 		return -EINVAL;
542773b11c2aSAndrii Nakryiko 
542873b11c2aSAndrii Nakryiko 	link = bpf_link_get_from_fd(attr->link_detach.link_fd);
542973b11c2aSAndrii Nakryiko 	if (IS_ERR(link))
543073b11c2aSAndrii Nakryiko 		return PTR_ERR(link);
543173b11c2aSAndrii Nakryiko 
543273b11c2aSAndrii Nakryiko 	if (link->ops->detach)
543373b11c2aSAndrii Nakryiko 		ret = link->ops->detach(link);
543473b11c2aSAndrii Nakryiko 	else
543573b11c2aSAndrii Nakryiko 		ret = -EOPNOTSUPP;
543673b11c2aSAndrii Nakryiko 
5437ab5d47bdSSebastian Andrzej Siewior 	bpf_link_put_direct(link);
543873b11c2aSAndrii Nakryiko 	return ret;
543973b11c2aSAndrii Nakryiko }
544073b11c2aSAndrii Nakryiko 
bpf_link_inc_not_zero(struct bpf_link * link)544167c3e835SKui-Feng Lee struct bpf_link *bpf_link_inc_not_zero(struct bpf_link *link)
54422d602c8cSAndrii Nakryiko {
5443005142b8SAlexei Starovoitov 	return atomic64_fetch_add_unless(&link->refcnt, 1, 0) ? link : ERR_PTR(-ENOENT);
5444005142b8SAlexei Starovoitov }
544567c3e835SKui-Feng Lee EXPORT_SYMBOL(bpf_link_inc_not_zero);
5446005142b8SAlexei Starovoitov 
bpf_link_by_id(u32 id)5447005142b8SAlexei Starovoitov struct bpf_link *bpf_link_by_id(u32 id)
5448005142b8SAlexei Starovoitov {
5449005142b8SAlexei Starovoitov 	struct bpf_link *link;
5450005142b8SAlexei Starovoitov 
5451005142b8SAlexei Starovoitov 	if (!id)
5452005142b8SAlexei Starovoitov 		return ERR_PTR(-ENOENT);
5453005142b8SAlexei Starovoitov 
5454005142b8SAlexei Starovoitov 	spin_lock_bh(&link_idr_lock);
5455005142b8SAlexei Starovoitov 	/* before link is "settled", ID is 0, pretend it doesn't exist yet */
5456005142b8SAlexei Starovoitov 	link = idr_find(&link_idr, id);
5457005142b8SAlexei Starovoitov 	if (link) {
5458005142b8SAlexei Starovoitov 		if (link->id)
5459005142b8SAlexei Starovoitov 			link = bpf_link_inc_not_zero(link);
5460005142b8SAlexei Starovoitov 		else
5461005142b8SAlexei Starovoitov 			link = ERR_PTR(-EAGAIN);
5462005142b8SAlexei Starovoitov 	} else {
5463005142b8SAlexei Starovoitov 		link = ERR_PTR(-ENOENT);
5464005142b8SAlexei Starovoitov 	}
5465005142b8SAlexei Starovoitov 	spin_unlock_bh(&link_idr_lock);
5466005142b8SAlexei Starovoitov 	return link;
54672d602c8cSAndrii Nakryiko }
54682d602c8cSAndrii Nakryiko 
bpf_link_get_curr_or_next(u32 * id)54699f883612SDmitrii Dolgov struct bpf_link *bpf_link_get_curr_or_next(u32 *id)
54709f883612SDmitrii Dolgov {
54719f883612SDmitrii Dolgov 	struct bpf_link *link;
54729f883612SDmitrii Dolgov 
54739f883612SDmitrii Dolgov 	spin_lock_bh(&link_idr_lock);
54749f883612SDmitrii Dolgov again:
54759f883612SDmitrii Dolgov 	link = idr_get_next(&link_idr, id);
54769f883612SDmitrii Dolgov 	if (link) {
54779f883612SDmitrii Dolgov 		link = bpf_link_inc_not_zero(link);
54789f883612SDmitrii Dolgov 		if (IS_ERR(link)) {
54799f883612SDmitrii Dolgov 			(*id)++;
54809f883612SDmitrii Dolgov 			goto again;
54819f883612SDmitrii Dolgov 		}
54829f883612SDmitrii Dolgov 	}
54839f883612SDmitrii Dolgov 	spin_unlock_bh(&link_idr_lock);
54849f883612SDmitrii Dolgov 
54859f883612SDmitrii Dolgov 	return link;
54869f883612SDmitrii Dolgov }
54879f883612SDmitrii Dolgov 
54882d602c8cSAndrii Nakryiko #define BPF_LINK_GET_FD_BY_ID_LAST_FIELD link_id
54892d602c8cSAndrii Nakryiko 
bpf_link_get_fd_by_id(const union bpf_attr * attr)54902d602c8cSAndrii Nakryiko static int bpf_link_get_fd_by_id(const union bpf_attr *attr)
54912d602c8cSAndrii Nakryiko {
54922d602c8cSAndrii Nakryiko 	struct bpf_link *link;
54932d602c8cSAndrii Nakryiko 	u32 id = attr->link_id;
5494005142b8SAlexei Starovoitov 	int fd;
54952d602c8cSAndrii Nakryiko 
54962d602c8cSAndrii Nakryiko 	if (CHECK_ATTR(BPF_LINK_GET_FD_BY_ID))
54972d602c8cSAndrii Nakryiko 		return -EINVAL;
54982d602c8cSAndrii Nakryiko 
54992d602c8cSAndrii Nakryiko 	if (!capable(CAP_SYS_ADMIN))
55002d602c8cSAndrii Nakryiko 		return -EPERM;
55012d602c8cSAndrii Nakryiko 
5502005142b8SAlexei Starovoitov 	link = bpf_link_by_id(id);
5503005142b8SAlexei Starovoitov 	if (IS_ERR(link))
5504005142b8SAlexei Starovoitov 		return PTR_ERR(link);
55052d602c8cSAndrii Nakryiko 
55062d602c8cSAndrii Nakryiko 	fd = bpf_link_new_fd(link);
55072d602c8cSAndrii Nakryiko 	if (fd < 0)
5508ab5d47bdSSebastian Andrzej Siewior 		bpf_link_put_direct(link);
55092d602c8cSAndrii Nakryiko 
55102d602c8cSAndrii Nakryiko 	return fd;
55112d602c8cSAndrii Nakryiko }
55122d602c8cSAndrii Nakryiko 
5513d46edd67SSong Liu DEFINE_MUTEX(bpf_stats_enabled_mutex);
5514d46edd67SSong Liu 
bpf_stats_release(struct inode * inode,struct file * file)5515d46edd67SSong Liu static int bpf_stats_release(struct inode *inode, struct file *file)
5516d46edd67SSong Liu {
5517d46edd67SSong Liu 	mutex_lock(&bpf_stats_enabled_mutex);
5518d46edd67SSong Liu 	static_key_slow_dec(&bpf_stats_enabled_key.key);
5519d46edd67SSong Liu 	mutex_unlock(&bpf_stats_enabled_mutex);
5520d46edd67SSong Liu 	return 0;
5521d46edd67SSong Liu }
5522d46edd67SSong Liu 
5523d46edd67SSong Liu static const struct file_operations bpf_stats_fops = {
5524d46edd67SSong Liu 	.release = bpf_stats_release,
5525d46edd67SSong Liu };
5526d46edd67SSong Liu 
bpf_enable_runtime_stats(void)5527d46edd67SSong Liu static int bpf_enable_runtime_stats(void)
5528d46edd67SSong Liu {
5529d46edd67SSong Liu 	int fd;
5530d46edd67SSong Liu 
5531d46edd67SSong Liu 	mutex_lock(&bpf_stats_enabled_mutex);
5532d46edd67SSong Liu 
5533d46edd67SSong Liu 	/* Set a very high limit to avoid overflow */
5534d46edd67SSong Liu 	if (static_key_count(&bpf_stats_enabled_key.key) > INT_MAX / 2) {
5535d46edd67SSong Liu 		mutex_unlock(&bpf_stats_enabled_mutex);
5536d46edd67SSong Liu 		return -EBUSY;
5537d46edd67SSong Liu 	}
5538d46edd67SSong Liu 
5539d46edd67SSong Liu 	fd = anon_inode_getfd("bpf-stats", &bpf_stats_fops, NULL, O_CLOEXEC);
5540d46edd67SSong Liu 	if (fd >= 0)
5541d46edd67SSong Liu 		static_key_slow_inc(&bpf_stats_enabled_key.key);
5542d46edd67SSong Liu 
5543d46edd67SSong Liu 	mutex_unlock(&bpf_stats_enabled_mutex);
5544d46edd67SSong Liu 	return fd;
5545d46edd67SSong Liu }
5546d46edd67SSong Liu 
5547d46edd67SSong Liu #define BPF_ENABLE_STATS_LAST_FIELD enable_stats.type
5548d46edd67SSong Liu 
bpf_enable_stats(union bpf_attr * attr)5549d46edd67SSong Liu static int bpf_enable_stats(union bpf_attr *attr)
5550d46edd67SSong Liu {
5551d46edd67SSong Liu 
5552d46edd67SSong Liu 	if (CHECK_ATTR(BPF_ENABLE_STATS))
5553d46edd67SSong Liu 		return -EINVAL;
5554d46edd67SSong Liu 
5555d46edd67SSong Liu 	if (!capable(CAP_SYS_ADMIN))
5556d46edd67SSong Liu 		return -EPERM;
5557d46edd67SSong Liu 
5558d46edd67SSong Liu 	switch (attr->enable_stats.type) {
5559d46edd67SSong Liu 	case BPF_STATS_RUN_TIME:
5560d46edd67SSong Liu 		return bpf_enable_runtime_stats();
5561d46edd67SSong Liu 	default:
5562d46edd67SSong Liu 		break;
5563d46edd67SSong Liu 	}
5564d46edd67SSong Liu 	return -EINVAL;
5565d46edd67SSong Liu }
5566d46edd67SSong Liu 
5567ac51d99bSYonghong Song #define BPF_ITER_CREATE_LAST_FIELD iter_create.flags
5568ac51d99bSYonghong Song 
bpf_iter_create(union bpf_attr * attr)5569ac51d99bSYonghong Song static int bpf_iter_create(union bpf_attr *attr)
5570ac51d99bSYonghong Song {
5571ac51d99bSYonghong Song 	struct bpf_link *link;
5572ac51d99bSYonghong Song 	int err;
5573ac51d99bSYonghong Song 
5574ac51d99bSYonghong Song 	if (CHECK_ATTR(BPF_ITER_CREATE))
5575ac51d99bSYonghong Song 		return -EINVAL;
5576ac51d99bSYonghong Song 
5577ac51d99bSYonghong Song 	if (attr->iter_create.flags)
5578ac51d99bSYonghong Song 		return -EINVAL;
5579ac51d99bSYonghong Song 
5580ac51d99bSYonghong Song 	link = bpf_link_get_from_fd(attr->iter_create.link_fd);
5581ac51d99bSYonghong Song 	if (IS_ERR(link))
5582ac51d99bSYonghong Song 		return PTR_ERR(link);
5583ac51d99bSYonghong Song 
5584ac51d99bSYonghong Song 	err = bpf_iter_new_fd(link);
5585ab5d47bdSSebastian Andrzej Siewior 	bpf_link_put_direct(link);
5586ac51d99bSYonghong Song 
5587ac51d99bSYonghong Song 	return err;
5588ac51d99bSYonghong Song }
5589ac51d99bSYonghong Song 
5590ef15314aSYiFei Zhu #define BPF_PROG_BIND_MAP_LAST_FIELD prog_bind_map.flags
5591ef15314aSYiFei Zhu 
bpf_prog_bind_map(union bpf_attr * attr)5592ef15314aSYiFei Zhu static int bpf_prog_bind_map(union bpf_attr *attr)
5593ef15314aSYiFei Zhu {
5594ef15314aSYiFei Zhu 	struct bpf_prog *prog;
5595ef15314aSYiFei Zhu 	struct bpf_map *map;
5596ef15314aSYiFei Zhu 	struct bpf_map **used_maps_old, **used_maps_new;
5597ef15314aSYiFei Zhu 	int i, ret = 0;
5598ef15314aSYiFei Zhu 
5599ef15314aSYiFei Zhu 	if (CHECK_ATTR(BPF_PROG_BIND_MAP))
5600ef15314aSYiFei Zhu 		return -EINVAL;
5601ef15314aSYiFei Zhu 
5602ef15314aSYiFei Zhu 	if (attr->prog_bind_map.flags)
5603ef15314aSYiFei Zhu 		return -EINVAL;
5604ef15314aSYiFei Zhu 
5605ef15314aSYiFei Zhu 	prog = bpf_prog_get(attr->prog_bind_map.prog_fd);
5606ef15314aSYiFei Zhu 	if (IS_ERR(prog))
5607ef15314aSYiFei Zhu 		return PTR_ERR(prog);
5608ef15314aSYiFei Zhu 
5609ef15314aSYiFei Zhu 	map = bpf_map_get(attr->prog_bind_map.map_fd);
5610ef15314aSYiFei Zhu 	if (IS_ERR(map)) {
5611ef15314aSYiFei Zhu 		ret = PTR_ERR(map);
5612ef15314aSYiFei Zhu 		goto out_prog_put;
5613ef15314aSYiFei Zhu 	}
5614ef15314aSYiFei Zhu 
5615ef15314aSYiFei Zhu 	mutex_lock(&prog->aux->used_maps_mutex);
5616ef15314aSYiFei Zhu 
5617ef15314aSYiFei Zhu 	used_maps_old = prog->aux->used_maps;
5618ef15314aSYiFei Zhu 
5619ef15314aSYiFei Zhu 	for (i = 0; i < prog->aux->used_map_cnt; i++)
56201028ae40SStanislav Fomichev 		if (used_maps_old[i] == map) {
56211028ae40SStanislav Fomichev 			bpf_map_put(map);
5622ef15314aSYiFei Zhu 			goto out_unlock;
56231028ae40SStanislav Fomichev 		}
5624ef15314aSYiFei Zhu 
5625ef15314aSYiFei Zhu 	used_maps_new = kmalloc_array(prog->aux->used_map_cnt + 1,
5626ef15314aSYiFei Zhu 				      sizeof(used_maps_new[0]),
5627ef15314aSYiFei Zhu 				      GFP_KERNEL);
5628ef15314aSYiFei Zhu 	if (!used_maps_new) {
5629ef15314aSYiFei Zhu 		ret = -ENOMEM;
5630ef15314aSYiFei Zhu 		goto out_unlock;
5631ef15314aSYiFei Zhu 	}
5632ef15314aSYiFei Zhu 
5633af66bfd3SHou Tao 	/* The bpf program will not access the bpf map, but for the sake of
5634af66bfd3SHou Tao 	 * simplicity, increase sleepable_refcnt for sleepable program as well.
5635af66bfd3SHou Tao 	 */
563666c84731SAndrii Nakryiko 	if (prog->sleepable)
5637af66bfd3SHou Tao 		atomic64_inc(&map->sleepable_refcnt);
5638ef15314aSYiFei Zhu 	memcpy(used_maps_new, used_maps_old,
5639ef15314aSYiFei Zhu 	       sizeof(used_maps_old[0]) * prog->aux->used_map_cnt);
5640ef15314aSYiFei Zhu 	used_maps_new[prog->aux->used_map_cnt] = map;
5641ef15314aSYiFei Zhu 
5642ef15314aSYiFei Zhu 	prog->aux->used_map_cnt++;
5643ef15314aSYiFei Zhu 	prog->aux->used_maps = used_maps_new;
5644ef15314aSYiFei Zhu 
5645ef15314aSYiFei Zhu 	kfree(used_maps_old);
5646ef15314aSYiFei Zhu 
5647ef15314aSYiFei Zhu out_unlock:
5648ef15314aSYiFei Zhu 	mutex_unlock(&prog->aux->used_maps_mutex);
5649ef15314aSYiFei Zhu 
5650ef15314aSYiFei Zhu 	if (ret)
5651ef15314aSYiFei Zhu 		bpf_map_put(map);
5652ef15314aSYiFei Zhu out_prog_put:
5653ef15314aSYiFei Zhu 	bpf_prog_put(prog);
5654ef15314aSYiFei Zhu 	return ret;
5655ef15314aSYiFei Zhu }
5656ef15314aSYiFei Zhu 
565735f96de0SAndrii Nakryiko #define BPF_TOKEN_CREATE_LAST_FIELD token_create.bpffs_fd
565835f96de0SAndrii Nakryiko 
token_create(union bpf_attr * attr)565935f96de0SAndrii Nakryiko static int token_create(union bpf_attr *attr)
566035f96de0SAndrii Nakryiko {
566135f96de0SAndrii Nakryiko 	if (CHECK_ATTR(BPF_TOKEN_CREATE))
566235f96de0SAndrii Nakryiko 		return -EINVAL;
566335f96de0SAndrii Nakryiko 
566435f96de0SAndrii Nakryiko 	/* no flags are supported yet */
566535f96de0SAndrii Nakryiko 	if (attr->token_create.flags)
566635f96de0SAndrii Nakryiko 		return -EINVAL;
566735f96de0SAndrii Nakryiko 
566835f96de0SAndrii Nakryiko 	return bpf_token_create(attr);
566935f96de0SAndrii Nakryiko }
567035f96de0SAndrii Nakryiko 
__sys_bpf(int cmd,bpfptr_t uattr,unsigned int size)5671af2ac3e1SAlexei Starovoitov static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size)
567299c55f7dSAlexei Starovoitov {
56738096f229SGreg Kroah-Hartman 	union bpf_attr attr;
567499c55f7dSAlexei Starovoitov 	int err;
567599c55f7dSAlexei Starovoitov 
5676dcab51f1SMartin KaFai Lau 	err = bpf_check_uarg_tail_zero(uattr, sizeof(attr), size);
567799c55f7dSAlexei Starovoitov 	if (err)
567899c55f7dSAlexei Starovoitov 		return err;
56791e270976SMartin KaFai Lau 	size = min_t(u32, size, sizeof(attr));
568099c55f7dSAlexei Starovoitov 
568199c55f7dSAlexei Starovoitov 	/* copy attributes from user space, may be less than sizeof(bpf_attr) */
56828096f229SGreg Kroah-Hartman 	memset(&attr, 0, sizeof(attr));
5683af2ac3e1SAlexei Starovoitov 	if (copy_from_bpfptr(&attr, uattr, size) != 0)
568499c55f7dSAlexei Starovoitov 		return -EFAULT;
568599c55f7dSAlexei Starovoitov 
5686afdb09c7SChenbo Feng 	err = security_bpf(cmd, &attr, size);
5687afdb09c7SChenbo Feng 	if (err < 0)
5688afdb09c7SChenbo Feng 		return err;
5689afdb09c7SChenbo Feng 
569099c55f7dSAlexei Starovoitov 	switch (cmd) {
569199c55f7dSAlexei Starovoitov 	case BPF_MAP_CREATE:
569299c55f7dSAlexei Starovoitov 		err = map_create(&attr);
569399c55f7dSAlexei Starovoitov 		break;
5694db20fd2bSAlexei Starovoitov 	case BPF_MAP_LOOKUP_ELEM:
5695db20fd2bSAlexei Starovoitov 		err = map_lookup_elem(&attr);
5696db20fd2bSAlexei Starovoitov 		break;
5697db20fd2bSAlexei Starovoitov 	case BPF_MAP_UPDATE_ELEM:
5698af2ac3e1SAlexei Starovoitov 		err = map_update_elem(&attr, uattr);
5699db20fd2bSAlexei Starovoitov 		break;
5700db20fd2bSAlexei Starovoitov 	case BPF_MAP_DELETE_ELEM:
5701b88df697SBenjamin Tissoires 		err = map_delete_elem(&attr, uattr);
5702db20fd2bSAlexei Starovoitov 		break;
5703db20fd2bSAlexei Starovoitov 	case BPF_MAP_GET_NEXT_KEY:
5704db20fd2bSAlexei Starovoitov 		err = map_get_next_key(&attr);
5705db20fd2bSAlexei Starovoitov 		break;
570687df15deSDaniel Borkmann 	case BPF_MAP_FREEZE:
570787df15deSDaniel Borkmann 		err = map_freeze(&attr);
570887df15deSDaniel Borkmann 		break;
570909756af4SAlexei Starovoitov 	case BPF_PROG_LOAD:
571047a71c1fSAndrii Nakryiko 		err = bpf_prog_load(&attr, uattr, size);
571109756af4SAlexei Starovoitov 		break;
5712b2197755SDaniel Borkmann 	case BPF_OBJ_PIN:
5713b2197755SDaniel Borkmann 		err = bpf_obj_pin(&attr);
5714b2197755SDaniel Borkmann 		break;
5715b2197755SDaniel Borkmann 	case BPF_OBJ_GET:
5716b2197755SDaniel Borkmann 		err = bpf_obj_get(&attr);
5717b2197755SDaniel Borkmann 		break;
5718f4324551SDaniel Mack 	case BPF_PROG_ATTACH:
5719f4324551SDaniel Mack 		err = bpf_prog_attach(&attr);
5720f4324551SDaniel Mack 		break;
5721f4324551SDaniel Mack 	case BPF_PROG_DETACH:
5722f4324551SDaniel Mack 		err = bpf_prog_detach(&attr);
5723f4324551SDaniel Mack 		break;
5724468e2f64SAlexei Starovoitov 	case BPF_PROG_QUERY:
5725af2ac3e1SAlexei Starovoitov 		err = bpf_prog_query(&attr, uattr.user);
5726468e2f64SAlexei Starovoitov 		break;
57271cf1cae9SAlexei Starovoitov 	case BPF_PROG_TEST_RUN:
5728af2ac3e1SAlexei Starovoitov 		err = bpf_prog_test_run(&attr, uattr.user);
57291cf1cae9SAlexei Starovoitov 		break;
573034ad5580SMartin KaFai Lau 	case BPF_PROG_GET_NEXT_ID:
5731af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
573234ad5580SMartin KaFai Lau 					  &prog_idr, &prog_idr_lock);
573334ad5580SMartin KaFai Lau 		break;
573434ad5580SMartin KaFai Lau 	case BPF_MAP_GET_NEXT_ID:
5735af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
573634ad5580SMartin KaFai Lau 					  &map_idr, &map_idr_lock);
573734ad5580SMartin KaFai Lau 		break;
57381b9ed84eSQuentin Monnet 	case BPF_BTF_GET_NEXT_ID:
5739af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
57401b9ed84eSQuentin Monnet 					  &btf_idr, &btf_idr_lock);
57411b9ed84eSQuentin Monnet 		break;
5742b16d9aa4SMartin KaFai Lau 	case BPF_PROG_GET_FD_BY_ID:
5743b16d9aa4SMartin KaFai Lau 		err = bpf_prog_get_fd_by_id(&attr);
5744b16d9aa4SMartin KaFai Lau 		break;
5745bd5f5f4eSMartin KaFai Lau 	case BPF_MAP_GET_FD_BY_ID:
5746bd5f5f4eSMartin KaFai Lau 		err = bpf_map_get_fd_by_id(&attr);
5747bd5f5f4eSMartin KaFai Lau 		break;
57481e270976SMartin KaFai Lau 	case BPF_OBJ_GET_INFO_BY_FD:
5749af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_info_by_fd(&attr, uattr.user);
57501e270976SMartin KaFai Lau 		break;
5751c4f6699dSAlexei Starovoitov 	case BPF_RAW_TRACEPOINT_OPEN:
5752c4f6699dSAlexei Starovoitov 		err = bpf_raw_tracepoint_open(&attr);
5753c4f6699dSAlexei Starovoitov 		break;
5754f56a653cSMartin KaFai Lau 	case BPF_BTF_LOAD:
575547a71c1fSAndrii Nakryiko 		err = bpf_btf_load(&attr, uattr, size);
5756f56a653cSMartin KaFai Lau 		break;
575778958fcaSMartin KaFai Lau 	case BPF_BTF_GET_FD_BY_ID:
575878958fcaSMartin KaFai Lau 		err = bpf_btf_get_fd_by_id(&attr);
575978958fcaSMartin KaFai Lau 		break;
576041bdc4b4SYonghong Song 	case BPF_TASK_FD_QUERY:
5761af2ac3e1SAlexei Starovoitov 		err = bpf_task_fd_query(&attr, uattr.user);
576241bdc4b4SYonghong Song 		break;
5763bd513cd0SMauricio Vasquez B 	case BPF_MAP_LOOKUP_AND_DELETE_ELEM:
5764bd513cd0SMauricio Vasquez B 		err = map_lookup_and_delete_elem(&attr);
5765bd513cd0SMauricio Vasquez B 		break;
5766cb4d03abSBrian Vazquez 	case BPF_MAP_LOOKUP_BATCH:
5767af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_LOOKUP_BATCH);
5768cb4d03abSBrian Vazquez 		break;
576905799638SYonghong Song 	case BPF_MAP_LOOKUP_AND_DELETE_BATCH:
5770af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user,
577105799638SYonghong Song 				       BPF_MAP_LOOKUP_AND_DELETE_BATCH);
577205799638SYonghong Song 		break;
5773aa2e93b8SBrian Vazquez 	case BPF_MAP_UPDATE_BATCH:
5774af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_UPDATE_BATCH);
5775aa2e93b8SBrian Vazquez 		break;
5776aa2e93b8SBrian Vazquez 	case BPF_MAP_DELETE_BATCH:
5777af2ac3e1SAlexei Starovoitov 		err = bpf_map_do_batch(&attr, uattr.user, BPF_MAP_DELETE_BATCH);
5778aa2e93b8SBrian Vazquez 		break;
5779af6eea57SAndrii Nakryiko 	case BPF_LINK_CREATE:
5780af2ac3e1SAlexei Starovoitov 		err = link_create(&attr, uattr);
5781af6eea57SAndrii Nakryiko 		break;
57820c991ebcSAndrii Nakryiko 	case BPF_LINK_UPDATE:
57830c991ebcSAndrii Nakryiko 		err = link_update(&attr);
57840c991ebcSAndrii Nakryiko 		break;
57852d602c8cSAndrii Nakryiko 	case BPF_LINK_GET_FD_BY_ID:
57862d602c8cSAndrii Nakryiko 		err = bpf_link_get_fd_by_id(&attr);
57872d602c8cSAndrii Nakryiko 		break;
57882d602c8cSAndrii Nakryiko 	case BPF_LINK_GET_NEXT_ID:
5789af2ac3e1SAlexei Starovoitov 		err = bpf_obj_get_next_id(&attr, uattr.user,
57902d602c8cSAndrii Nakryiko 					  &link_idr, &link_idr_lock);
57912d602c8cSAndrii Nakryiko 		break;
5792d46edd67SSong Liu 	case BPF_ENABLE_STATS:
5793d46edd67SSong Liu 		err = bpf_enable_stats(&attr);
5794d46edd67SSong Liu 		break;
5795ac51d99bSYonghong Song 	case BPF_ITER_CREATE:
5796ac51d99bSYonghong Song 		err = bpf_iter_create(&attr);
5797ac51d99bSYonghong Song 		break;
579873b11c2aSAndrii Nakryiko 	case BPF_LINK_DETACH:
579973b11c2aSAndrii Nakryiko 		err = link_detach(&attr);
580073b11c2aSAndrii Nakryiko 		break;
5801ef15314aSYiFei Zhu 	case BPF_PROG_BIND_MAP:
5802ef15314aSYiFei Zhu 		err = bpf_prog_bind_map(&attr);
5803ef15314aSYiFei Zhu 		break;
580435f96de0SAndrii Nakryiko 	case BPF_TOKEN_CREATE:
580535f96de0SAndrii Nakryiko 		err = token_create(&attr);
580635f96de0SAndrii Nakryiko 		break;
580799c55f7dSAlexei Starovoitov 	default:
580899c55f7dSAlexei Starovoitov 		err = -EINVAL;
580999c55f7dSAlexei Starovoitov 		break;
581099c55f7dSAlexei Starovoitov 	}
581199c55f7dSAlexei Starovoitov 
581299c55f7dSAlexei Starovoitov 	return err;
581399c55f7dSAlexei Starovoitov }
581479a7f8bdSAlexei Starovoitov 
SYSCALL_DEFINE3(bpf,int,cmd,union bpf_attr __user *,uattr,unsigned int,size)5815af2ac3e1SAlexei Starovoitov SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
5816af2ac3e1SAlexei Starovoitov {
5817af2ac3e1SAlexei Starovoitov 	return __sys_bpf(cmd, USER_BPFPTR(uattr), size);
5818af2ac3e1SAlexei Starovoitov }
5819af2ac3e1SAlexei Starovoitov 
syscall_prog_is_valid_access(int off,int size,enum bpf_access_type type,const struct bpf_prog * prog,struct bpf_insn_access_aux * info)582079a7f8bdSAlexei Starovoitov static bool syscall_prog_is_valid_access(int off, int size,
582179a7f8bdSAlexei Starovoitov 					 enum bpf_access_type type,
582279a7f8bdSAlexei Starovoitov 					 const struct bpf_prog *prog,
582379a7f8bdSAlexei Starovoitov 					 struct bpf_insn_access_aux *info)
582479a7f8bdSAlexei Starovoitov {
582579a7f8bdSAlexei Starovoitov 	if (off < 0 || off >= U16_MAX)
582679a7f8bdSAlexei Starovoitov 		return false;
582779a7f8bdSAlexei Starovoitov 	if (off % size != 0)
582879a7f8bdSAlexei Starovoitov 		return false;
582979a7f8bdSAlexei Starovoitov 	return true;
583079a7f8bdSAlexei Starovoitov }
583179a7f8bdSAlexei Starovoitov 
BPF_CALL_3(bpf_sys_bpf,int,cmd,union bpf_attr *,attr,u32,attr_size)5832b1d18a75SAlexei Starovoitov BPF_CALL_3(bpf_sys_bpf, int, cmd, union bpf_attr *, attr, u32, attr_size)
583379a7f8bdSAlexei Starovoitov {
5834af2ac3e1SAlexei Starovoitov 	switch (cmd) {
5835af2ac3e1SAlexei Starovoitov 	case BPF_MAP_CREATE:
5836b88df697SBenjamin Tissoires 	case BPF_MAP_DELETE_ELEM:
5837af2ac3e1SAlexei Starovoitov 	case BPF_MAP_UPDATE_ELEM:
5838af2ac3e1SAlexei Starovoitov 	case BPF_MAP_FREEZE:
5839b88df697SBenjamin Tissoires 	case BPF_MAP_GET_FD_BY_ID:
5840af2ac3e1SAlexei Starovoitov 	case BPF_PROG_LOAD:
5841c571bd75SAlexei Starovoitov 	case BPF_BTF_LOAD:
5842b1d18a75SAlexei Starovoitov 	case BPF_LINK_CREATE:
5843b1d18a75SAlexei Starovoitov 	case BPF_RAW_TRACEPOINT_OPEN:
5844af2ac3e1SAlexei Starovoitov 		break;
584586f44fceSAlexei Starovoitov 	default:
584686f44fceSAlexei Starovoitov 		return -EINVAL;
584786f44fceSAlexei Starovoitov 	}
584886f44fceSAlexei Starovoitov 	return __sys_bpf(cmd, KERNEL_BPFPTR(attr), attr_size);
584986f44fceSAlexei Starovoitov }
585086f44fceSAlexei Starovoitov 
58514e4588f1SAlexei Starovoitov 
58524e4588f1SAlexei Starovoitov /* To shut up -Wmissing-prototypes.
58534e4588f1SAlexei Starovoitov  * This function is used by the kernel light skeleton
58544e4588f1SAlexei Starovoitov  * to load bpf programs when modules are loaded or during kernel boot.
58554e4588f1SAlexei Starovoitov  * See tools/lib/bpf/skel_internal.h
58564e4588f1SAlexei Starovoitov  */
58574e4588f1SAlexei Starovoitov int kern_sys_bpf(int cmd, union bpf_attr *attr, unsigned int size);
58584e4588f1SAlexei Starovoitov 
kern_sys_bpf(int cmd,union bpf_attr * attr,unsigned int size)585986f44fceSAlexei Starovoitov int kern_sys_bpf(int cmd, union bpf_attr *attr, unsigned int size)
586086f44fceSAlexei Starovoitov {
586186f44fceSAlexei Starovoitov 	struct bpf_prog * __maybe_unused prog;
586286f44fceSAlexei Starovoitov 	struct bpf_tramp_run_ctx __maybe_unused run_ctx;
586386f44fceSAlexei Starovoitov 
586486f44fceSAlexei Starovoitov 	switch (cmd) {
5865b1d18a75SAlexei Starovoitov #ifdef CONFIG_BPF_JIT /* __bpf_prog_enter_sleepable used by trampoline and JIT */
5866b1d18a75SAlexei Starovoitov 	case BPF_PROG_TEST_RUN:
5867b1d18a75SAlexei Starovoitov 		if (attr->test.data_in || attr->test.data_out ||
5868b1d18a75SAlexei Starovoitov 		    attr->test.ctx_out || attr->test.duration ||
5869b1d18a75SAlexei Starovoitov 		    attr->test.repeat || attr->test.flags)
5870b1d18a75SAlexei Starovoitov 			return -EINVAL;
5871b1d18a75SAlexei Starovoitov 
5872b1d18a75SAlexei Starovoitov 		prog = bpf_prog_get_type(attr->test.prog_fd, BPF_PROG_TYPE_SYSCALL);
5873b1d18a75SAlexei Starovoitov 		if (IS_ERR(prog))
5874b1d18a75SAlexei Starovoitov 			return PTR_ERR(prog);
5875b1d18a75SAlexei Starovoitov 
5876b1d18a75SAlexei Starovoitov 		if (attr->test.ctx_size_in < prog->aux->max_ctx_offset ||
5877b1d18a75SAlexei Starovoitov 		    attr->test.ctx_size_in > U16_MAX) {
5878b1d18a75SAlexei Starovoitov 			bpf_prog_put(prog);
5879b1d18a75SAlexei Starovoitov 			return -EINVAL;
5880b1d18a75SAlexei Starovoitov 		}
5881b1d18a75SAlexei Starovoitov 
5882e384c7b7SKui-Feng Lee 		run_ctx.bpf_cookie = 0;
5883271de525SMartin KaFai Lau 		if (!__bpf_prog_enter_sleepable_recur(prog, &run_ctx)) {
5884b1d18a75SAlexei Starovoitov 			/* recursion detected */
58857645629fSSebastian Andrzej Siewior 			__bpf_prog_exit_sleepable_recur(prog, 0, &run_ctx);
5886b1d18a75SAlexei Starovoitov 			bpf_prog_put(prog);
5887b1d18a75SAlexei Starovoitov 			return -EBUSY;
5888b1d18a75SAlexei Starovoitov 		}
5889b1d18a75SAlexei Starovoitov 		attr->test.retval = bpf_prog_run(prog, (void *) (long) attr->test.ctx_in);
5890271de525SMartin KaFai Lau 		__bpf_prog_exit_sleepable_recur(prog, 0 /* bpf_prog_run does runtime stats */,
5891271de525SMartin KaFai Lau 						&run_ctx);
5892b1d18a75SAlexei Starovoitov 		bpf_prog_put(prog);
5893b1d18a75SAlexei Starovoitov 		return 0;
5894b1d18a75SAlexei Starovoitov #endif
5895af2ac3e1SAlexei Starovoitov 	default:
589686f44fceSAlexei Starovoitov 		return ____bpf_sys_bpf(cmd, attr, size);
589779a7f8bdSAlexei Starovoitov 	}
5898af2ac3e1SAlexei Starovoitov }
589986f44fceSAlexei Starovoitov EXPORT_SYMBOL(kern_sys_bpf);
590079a7f8bdSAlexei Starovoitov 
59013a2daa72SPu Lehui static const struct bpf_func_proto bpf_sys_bpf_proto = {
590279a7f8bdSAlexei Starovoitov 	.func		= bpf_sys_bpf,
590379a7f8bdSAlexei Starovoitov 	.gpl_only	= false,
590479a7f8bdSAlexei Starovoitov 	.ret_type	= RET_INTEGER,
590579a7f8bdSAlexei Starovoitov 	.arg1_type	= ARG_ANYTHING,
5906216e3cd2SHao Luo 	.arg2_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
590779a7f8bdSAlexei Starovoitov 	.arg3_type	= ARG_CONST_SIZE,
590879a7f8bdSAlexei Starovoitov };
590979a7f8bdSAlexei Starovoitov 
591079a7f8bdSAlexei Starovoitov const struct bpf_func_proto * __weak
tracing_prog_func_proto(enum bpf_func_id func_id,const struct bpf_prog * prog)591179a7f8bdSAlexei Starovoitov tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
591279a7f8bdSAlexei Starovoitov {
5913bbc1d247SAndrii Nakryiko 	return bpf_base_func_proto(func_id, prog);
591479a7f8bdSAlexei Starovoitov }
591579a7f8bdSAlexei Starovoitov 
BPF_CALL_1(bpf_sys_close,u32,fd)59163abea089SAlexei Starovoitov BPF_CALL_1(bpf_sys_close, u32, fd)
59173abea089SAlexei Starovoitov {
59183abea089SAlexei Starovoitov 	/* When bpf program calls this helper there should not be
59193abea089SAlexei Starovoitov 	 * an fdget() without matching completed fdput().
59203abea089SAlexei Starovoitov 	 * This helper is allowed in the following callchain only:
59213abea089SAlexei Starovoitov 	 * sys_bpf->prog_test_run->bpf_prog->bpf_sys_close
59223abea089SAlexei Starovoitov 	 */
59233abea089SAlexei Starovoitov 	return close_fd(fd);
59243abea089SAlexei Starovoitov }
59253abea089SAlexei Starovoitov 
59263a2daa72SPu Lehui static const struct bpf_func_proto bpf_sys_close_proto = {
59273abea089SAlexei Starovoitov 	.func		= bpf_sys_close,
59283abea089SAlexei Starovoitov 	.gpl_only	= false,
59293abea089SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
59303abea089SAlexei Starovoitov 	.arg1_type	= ARG_ANYTHING,
59313abea089SAlexei Starovoitov };
59323abea089SAlexei Starovoitov 
BPF_CALL_4(bpf_kallsyms_lookup_name,const char *,name,int,name_sz,int,flags,u64 *,res)5933d6aef08aSKumar Kartikeya Dwivedi BPF_CALL_4(bpf_kallsyms_lookup_name, const char *, name, int, name_sz, int, flags, u64 *, res)
5934d6aef08aSKumar Kartikeya Dwivedi {
5935d6aef08aSKumar Kartikeya Dwivedi 	if (flags)
5936d6aef08aSKumar Kartikeya Dwivedi 		return -EINVAL;
5937d6aef08aSKumar Kartikeya Dwivedi 
5938d6aef08aSKumar Kartikeya Dwivedi 	if (name_sz <= 1 || name[name_sz - 1])
5939d6aef08aSKumar Kartikeya Dwivedi 		return -EINVAL;
5940d6aef08aSKumar Kartikeya Dwivedi 
5941d6aef08aSKumar Kartikeya Dwivedi 	if (!bpf_dump_raw_ok(current_cred()))
5942d6aef08aSKumar Kartikeya Dwivedi 		return -EPERM;
5943d6aef08aSKumar Kartikeya Dwivedi 
5944d6aef08aSKumar Kartikeya Dwivedi 	*res = kallsyms_lookup_name(name);
5945d6aef08aSKumar Kartikeya Dwivedi 	return *res ? 0 : -ENOENT;
5946d6aef08aSKumar Kartikeya Dwivedi }
5947d6aef08aSKumar Kartikeya Dwivedi 
5948dc368e1cSJoanne Koong static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
5949d6aef08aSKumar Kartikeya Dwivedi 	.func		= bpf_kallsyms_lookup_name,
5950d6aef08aSKumar Kartikeya Dwivedi 	.gpl_only	= false,
5951d6aef08aSKumar Kartikeya Dwivedi 	.ret_type	= RET_INTEGER,
5952d6aef08aSKumar Kartikeya Dwivedi 	.arg1_type	= ARG_PTR_TO_MEM,
5953d4efb170SKumar Kartikeya Dwivedi 	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
5954d6aef08aSKumar Kartikeya Dwivedi 	.arg3_type	= ARG_ANYTHING,
5955d6aef08aSKumar Kartikeya Dwivedi 	.arg4_type	= ARG_PTR_TO_LONG,
5956d6aef08aSKumar Kartikeya Dwivedi };
5957d6aef08aSKumar Kartikeya Dwivedi 
595879a7f8bdSAlexei Starovoitov static const struct bpf_func_proto *
syscall_prog_func_proto(enum bpf_func_id func_id,const struct bpf_prog * prog)595979a7f8bdSAlexei Starovoitov syscall_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
596079a7f8bdSAlexei Starovoitov {
596179a7f8bdSAlexei Starovoitov 	switch (func_id) {
596279a7f8bdSAlexei Starovoitov 	case BPF_FUNC_sys_bpf:
5963bbc1d247SAndrii Nakryiko 		return !bpf_token_capable(prog->aux->token, CAP_PERFMON)
5964bbc1d247SAndrii Nakryiko 		       ? NULL : &bpf_sys_bpf_proto;
59653d78417bSAlexei Starovoitov 	case BPF_FUNC_btf_find_by_name_kind:
59663d78417bSAlexei Starovoitov 		return &bpf_btf_find_by_name_kind_proto;
59673abea089SAlexei Starovoitov 	case BPF_FUNC_sys_close:
59683abea089SAlexei Starovoitov 		return &bpf_sys_close_proto;
5969d6aef08aSKumar Kartikeya Dwivedi 	case BPF_FUNC_kallsyms_lookup_name:
5970d6aef08aSKumar Kartikeya Dwivedi 		return &bpf_kallsyms_lookup_name_proto;
597179a7f8bdSAlexei Starovoitov 	default:
597279a7f8bdSAlexei Starovoitov 		return tracing_prog_func_proto(func_id, prog);
597379a7f8bdSAlexei Starovoitov 	}
597479a7f8bdSAlexei Starovoitov }
597579a7f8bdSAlexei Starovoitov 
597679a7f8bdSAlexei Starovoitov const struct bpf_verifier_ops bpf_syscall_verifier_ops = {
597779a7f8bdSAlexei Starovoitov 	.get_func_proto  = syscall_prog_func_proto,
597879a7f8bdSAlexei Starovoitov 	.is_valid_access = syscall_prog_is_valid_access,
597979a7f8bdSAlexei Starovoitov };
598079a7f8bdSAlexei Starovoitov 
598179a7f8bdSAlexei Starovoitov const struct bpf_prog_ops bpf_syscall_prog_ops = {
598279a7f8bdSAlexei Starovoitov 	.test_run = bpf_prog_test_run_syscall,
598379a7f8bdSAlexei Starovoitov };
59842900005eSYan Zhu 
59852900005eSYan Zhu #ifdef CONFIG_SYSCTL
bpf_stats_handler(const struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)5986*78eb4ea2SJoel Granados static int bpf_stats_handler(const struct ctl_table *table, int write,
59872900005eSYan Zhu 			     void *buffer, size_t *lenp, loff_t *ppos)
59882900005eSYan Zhu {
59892900005eSYan Zhu 	struct static_key *key = (struct static_key *)table->data;
59902900005eSYan Zhu 	static int saved_val;
59912900005eSYan Zhu 	int val, ret;
59922900005eSYan Zhu 	struct ctl_table tmp = {
59932900005eSYan Zhu 		.data   = &val,
59942900005eSYan Zhu 		.maxlen = sizeof(val),
59952900005eSYan Zhu 		.mode   = table->mode,
59962900005eSYan Zhu 		.extra1 = SYSCTL_ZERO,
59972900005eSYan Zhu 		.extra2 = SYSCTL_ONE,
59982900005eSYan Zhu 	};
59992900005eSYan Zhu 
60002900005eSYan Zhu 	if (write && !capable(CAP_SYS_ADMIN))
60012900005eSYan Zhu 		return -EPERM;
60022900005eSYan Zhu 
60032900005eSYan Zhu 	mutex_lock(&bpf_stats_enabled_mutex);
60042900005eSYan Zhu 	val = saved_val;
60052900005eSYan Zhu 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
60062900005eSYan Zhu 	if (write && !ret && val != saved_val) {
60072900005eSYan Zhu 		if (val)
60082900005eSYan Zhu 			static_key_slow_inc(key);
60092900005eSYan Zhu 		else
60102900005eSYan Zhu 			static_key_slow_dec(key);
60112900005eSYan Zhu 		saved_val = val;
60122900005eSYan Zhu 	}
60132900005eSYan Zhu 	mutex_unlock(&bpf_stats_enabled_mutex);
60142900005eSYan Zhu 	return ret;
60152900005eSYan Zhu }
60162900005eSYan Zhu 
unpriv_ebpf_notify(int new_state)60172900005eSYan Zhu void __weak unpriv_ebpf_notify(int new_state)
60182900005eSYan Zhu {
60192900005eSYan Zhu }
60202900005eSYan Zhu 
bpf_unpriv_handler(const struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)6021*78eb4ea2SJoel Granados static int bpf_unpriv_handler(const struct ctl_table *table, int write,
60222900005eSYan Zhu 			      void *buffer, size_t *lenp, loff_t *ppos)
60232900005eSYan Zhu {
60242900005eSYan Zhu 	int ret, unpriv_enable = *(int *)table->data;
60252900005eSYan Zhu 	bool locked_state = unpriv_enable == 1;
60262900005eSYan Zhu 	struct ctl_table tmp = *table;
60272900005eSYan Zhu 
60282900005eSYan Zhu 	if (write && !capable(CAP_SYS_ADMIN))
60292900005eSYan Zhu 		return -EPERM;
60302900005eSYan Zhu 
60312900005eSYan Zhu 	tmp.data = &unpriv_enable;
60322900005eSYan Zhu 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
60332900005eSYan Zhu 	if (write && !ret) {
60342900005eSYan Zhu 		if (locked_state && unpriv_enable != 1)
60352900005eSYan Zhu 			return -EPERM;
60362900005eSYan Zhu 		*(int *)table->data = unpriv_enable;
60372900005eSYan Zhu 	}
60382900005eSYan Zhu 
6039fedf9920SKui-Feng Lee 	if (write)
60402900005eSYan Zhu 		unpriv_ebpf_notify(unpriv_enable);
60412900005eSYan Zhu 
60422900005eSYan Zhu 	return ret;
60432900005eSYan Zhu }
60442900005eSYan Zhu 
60452900005eSYan Zhu static struct ctl_table bpf_syscall_table[] = {
60462900005eSYan Zhu 	{
60472900005eSYan Zhu 		.procname	= "unprivileged_bpf_disabled",
60482900005eSYan Zhu 		.data		= &sysctl_unprivileged_bpf_disabled,
60492900005eSYan Zhu 		.maxlen		= sizeof(sysctl_unprivileged_bpf_disabled),
60502900005eSYan Zhu 		.mode		= 0644,
60512900005eSYan Zhu 		.proc_handler	= bpf_unpriv_handler,
60522900005eSYan Zhu 		.extra1		= SYSCTL_ZERO,
60532900005eSYan Zhu 		.extra2		= SYSCTL_TWO,
60542900005eSYan Zhu 	},
60552900005eSYan Zhu 	{
60562900005eSYan Zhu 		.procname	= "bpf_stats_enabled",
60572900005eSYan Zhu 		.data		= &bpf_stats_enabled_key.key,
60582900005eSYan Zhu 		.mode		= 0644,
60592900005eSYan Zhu 		.proc_handler	= bpf_stats_handler,
60602900005eSYan Zhu 	},
60612900005eSYan Zhu };
60622900005eSYan Zhu 
bpf_syscall_sysctl_init(void)60632900005eSYan Zhu static int __init bpf_syscall_sysctl_init(void)
60642900005eSYan Zhu {
60652900005eSYan Zhu 	register_sysctl_init("kernel", bpf_syscall_table);
60662900005eSYan Zhu 	return 0;
60672900005eSYan Zhu }
60682900005eSYan Zhu late_initcall(bpf_syscall_sysctl_init);
60692900005eSYan Zhu #endif /* CONFIG_SYSCTL */
6070