xref: /openbmc/linux/kernel/bpf/helpers.c (revision 5ca7867078296cfa9c100f9a3b2d24be1e139825)
15b497af4SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2d0003ec0SAlexei Starovoitov /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
3d0003ec0SAlexei Starovoitov  */
4d0003ec0SAlexei Starovoitov #include <linux/bpf.h>
53bd916eeSYonghong Song #include <linux/btf.h>
6aef2fedaSJakub Kicinski #include <linux/bpf-cgroup.h>
7fda01efcSDavid Vernet #include <linux/cgroup.h>
8d0003ec0SAlexei Starovoitov #include <linux/rcupdate.h>
903e69b50SDaniel Borkmann #include <linux/random.h>
10c04167ceSDaniel Borkmann #include <linux/smp.h>
112d0e30c3SDaniel Borkmann #include <linux/topology.h>
1217ca8cbfSDaniel Borkmann #include <linux/ktime.h>
13ffeedafbSAlexei Starovoitov #include <linux/sched.h>
14ffeedafbSAlexei Starovoitov #include <linux/uidgid.h>
15f3694e00SDaniel Borkmann #include <linux/filter.h>
16d7a4cb9bSAndrey Ignatov #include <linux/ctype.h>
175576b991SMartin KaFai Lau #include <linux/jiffies.h>
18b4490c5cSCarlos Neira #include <linux/pid_namespace.h>
1947e34cb7SDave Marchevsky #include <linux/poison.h>
20b4490c5cSCarlos Neira #include <linux/proc_ns.h>
21ff40e510SDaniel Borkmann #include <linux/security.h>
22376040e4SKenny Yu #include <linux/btf_ids.h>
23958cf2e2SKumar Kartikeya Dwivedi #include <linux/bpf_mem_alloc.h>
24d7a4cb9bSAndrey Ignatov 
25d7a4cb9bSAndrey Ignatov #include "../../lib/kstrtox.h"
26d0003ec0SAlexei Starovoitov 
27d0003ec0SAlexei Starovoitov /* If kernel subsystem is allowing eBPF programs to call this function,
28d0003ec0SAlexei Starovoitov  * inside its own verifier_ops->get_func_proto() callback it should return
29d0003ec0SAlexei Starovoitov  * bpf_map_lookup_elem_proto, so that verifier can properly check the arguments
30d0003ec0SAlexei Starovoitov  *
31d0003ec0SAlexei Starovoitov  * Different map implementations will rely on rcu in map methods
32d0003ec0SAlexei Starovoitov  * lookup/update/delete, therefore eBPF programs must run under rcu lock
33d0003ec0SAlexei Starovoitov  * if program is allowed to access maps, so check rcu_read_lock_held in
34d0003ec0SAlexei Starovoitov  * all three functions.
35d0003ec0SAlexei Starovoitov  */
36f3694e00SDaniel Borkmann BPF_CALL_2(bpf_map_lookup_elem, struct bpf_map *, map, void *, key)
37d0003ec0SAlexei Starovoitov {
38694cea39SToke Høiland-Jørgensen 	WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
39f3694e00SDaniel Borkmann 	return (unsigned long) map->ops->map_lookup_elem(map, key);
40d0003ec0SAlexei Starovoitov }
41d0003ec0SAlexei Starovoitov 
42a2c83fffSDaniel Borkmann const struct bpf_func_proto bpf_map_lookup_elem_proto = {
43d0003ec0SAlexei Starovoitov 	.func		= bpf_map_lookup_elem,
44d0003ec0SAlexei Starovoitov 	.gpl_only	= false,
4536bbef52SDaniel Borkmann 	.pkt_access	= true,
46d0003ec0SAlexei Starovoitov 	.ret_type	= RET_PTR_TO_MAP_VALUE_OR_NULL,
47d0003ec0SAlexei Starovoitov 	.arg1_type	= ARG_CONST_MAP_PTR,
48d0003ec0SAlexei Starovoitov 	.arg2_type	= ARG_PTR_TO_MAP_KEY,
49d0003ec0SAlexei Starovoitov };
50d0003ec0SAlexei Starovoitov 
51f3694e00SDaniel Borkmann BPF_CALL_4(bpf_map_update_elem, struct bpf_map *, map, void *, key,
52f3694e00SDaniel Borkmann 	   void *, value, u64, flags)
53d0003ec0SAlexei Starovoitov {
54694cea39SToke Høiland-Jørgensen 	WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
55f3694e00SDaniel Borkmann 	return map->ops->map_update_elem(map, key, value, flags);
56d0003ec0SAlexei Starovoitov }
57d0003ec0SAlexei Starovoitov 
58a2c83fffSDaniel Borkmann const struct bpf_func_proto bpf_map_update_elem_proto = {
59d0003ec0SAlexei Starovoitov 	.func		= bpf_map_update_elem,
60d0003ec0SAlexei Starovoitov 	.gpl_only	= false,
6136bbef52SDaniel Borkmann 	.pkt_access	= true,
62d0003ec0SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
63d0003ec0SAlexei Starovoitov 	.arg1_type	= ARG_CONST_MAP_PTR,
64d0003ec0SAlexei Starovoitov 	.arg2_type	= ARG_PTR_TO_MAP_KEY,
65d0003ec0SAlexei Starovoitov 	.arg3_type	= ARG_PTR_TO_MAP_VALUE,
66d0003ec0SAlexei Starovoitov 	.arg4_type	= ARG_ANYTHING,
67d0003ec0SAlexei Starovoitov };
68d0003ec0SAlexei Starovoitov 
69f3694e00SDaniel Borkmann BPF_CALL_2(bpf_map_delete_elem, struct bpf_map *, map, void *, key)
70d0003ec0SAlexei Starovoitov {
71694cea39SToke Høiland-Jørgensen 	WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
72d0003ec0SAlexei Starovoitov 	return map->ops->map_delete_elem(map, key);
73d0003ec0SAlexei Starovoitov }
74d0003ec0SAlexei Starovoitov 
75a2c83fffSDaniel Borkmann const struct bpf_func_proto bpf_map_delete_elem_proto = {
76d0003ec0SAlexei Starovoitov 	.func		= bpf_map_delete_elem,
77d0003ec0SAlexei Starovoitov 	.gpl_only	= false,
7836bbef52SDaniel Borkmann 	.pkt_access	= true,
79d0003ec0SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
80d0003ec0SAlexei Starovoitov 	.arg1_type	= ARG_CONST_MAP_PTR,
81d0003ec0SAlexei Starovoitov 	.arg2_type	= ARG_PTR_TO_MAP_KEY,
82d0003ec0SAlexei Starovoitov };
8303e69b50SDaniel Borkmann 
84f1a2e44aSMauricio Vasquez B BPF_CALL_3(bpf_map_push_elem, struct bpf_map *, map, void *, value, u64, flags)
85f1a2e44aSMauricio Vasquez B {
86f1a2e44aSMauricio Vasquez B 	return map->ops->map_push_elem(map, value, flags);
87f1a2e44aSMauricio Vasquez B }
88f1a2e44aSMauricio Vasquez B 
89f1a2e44aSMauricio Vasquez B const struct bpf_func_proto bpf_map_push_elem_proto = {
90f1a2e44aSMauricio Vasquez B 	.func		= bpf_map_push_elem,
91f1a2e44aSMauricio Vasquez B 	.gpl_only	= false,
92f1a2e44aSMauricio Vasquez B 	.pkt_access	= true,
93f1a2e44aSMauricio Vasquez B 	.ret_type	= RET_INTEGER,
94f1a2e44aSMauricio Vasquez B 	.arg1_type	= ARG_CONST_MAP_PTR,
95f1a2e44aSMauricio Vasquez B 	.arg2_type	= ARG_PTR_TO_MAP_VALUE,
96f1a2e44aSMauricio Vasquez B 	.arg3_type	= ARG_ANYTHING,
97f1a2e44aSMauricio Vasquez B };
98f1a2e44aSMauricio Vasquez B 
99f1a2e44aSMauricio Vasquez B BPF_CALL_2(bpf_map_pop_elem, struct bpf_map *, map, void *, value)
100f1a2e44aSMauricio Vasquez B {
101f1a2e44aSMauricio Vasquez B 	return map->ops->map_pop_elem(map, value);
102f1a2e44aSMauricio Vasquez B }
103f1a2e44aSMauricio Vasquez B 
104f1a2e44aSMauricio Vasquez B const struct bpf_func_proto bpf_map_pop_elem_proto = {
105f1a2e44aSMauricio Vasquez B 	.func		= bpf_map_pop_elem,
106f1a2e44aSMauricio Vasquez B 	.gpl_only	= false,
107f1a2e44aSMauricio Vasquez B 	.ret_type	= RET_INTEGER,
108f1a2e44aSMauricio Vasquez B 	.arg1_type	= ARG_CONST_MAP_PTR,
10916d1e00cSJoanne Koong 	.arg2_type	= ARG_PTR_TO_MAP_VALUE | MEM_UNINIT,
110f1a2e44aSMauricio Vasquez B };
111f1a2e44aSMauricio Vasquez B 
112f1a2e44aSMauricio Vasquez B BPF_CALL_2(bpf_map_peek_elem, struct bpf_map *, map, void *, value)
113f1a2e44aSMauricio Vasquez B {
114f1a2e44aSMauricio Vasquez B 	return map->ops->map_peek_elem(map, value);
115f1a2e44aSMauricio Vasquez B }
116f1a2e44aSMauricio Vasquez B 
117f1a2e44aSMauricio Vasquez B const struct bpf_func_proto bpf_map_peek_elem_proto = {
118301a33d5SMircea Cirjaliu 	.func		= bpf_map_peek_elem,
119f1a2e44aSMauricio Vasquez B 	.gpl_only	= false,
120f1a2e44aSMauricio Vasquez B 	.ret_type	= RET_INTEGER,
121f1a2e44aSMauricio Vasquez B 	.arg1_type	= ARG_CONST_MAP_PTR,
12216d1e00cSJoanne Koong 	.arg2_type	= ARG_PTR_TO_MAP_VALUE | MEM_UNINIT,
123f1a2e44aSMauricio Vasquez B };
124f1a2e44aSMauricio Vasquez B 
12507343110SFeng Zhou BPF_CALL_3(bpf_map_lookup_percpu_elem, struct bpf_map *, map, void *, key, u32, cpu)
12607343110SFeng Zhou {
12707343110SFeng Zhou 	WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
12807343110SFeng Zhou 	return (unsigned long) map->ops->map_lookup_percpu_elem(map, key, cpu);
12907343110SFeng Zhou }
13007343110SFeng Zhou 
13107343110SFeng Zhou const struct bpf_func_proto bpf_map_lookup_percpu_elem_proto = {
13207343110SFeng Zhou 	.func		= bpf_map_lookup_percpu_elem,
13307343110SFeng Zhou 	.gpl_only	= false,
13407343110SFeng Zhou 	.pkt_access	= true,
13507343110SFeng Zhou 	.ret_type	= RET_PTR_TO_MAP_VALUE_OR_NULL,
13607343110SFeng Zhou 	.arg1_type	= ARG_CONST_MAP_PTR,
13707343110SFeng Zhou 	.arg2_type	= ARG_PTR_TO_MAP_KEY,
13807343110SFeng Zhou 	.arg3_type	= ARG_ANYTHING,
13907343110SFeng Zhou };
14007343110SFeng Zhou 
14103e69b50SDaniel Borkmann const struct bpf_func_proto bpf_get_prandom_u32_proto = {
1423ad00405SDaniel Borkmann 	.func		= bpf_user_rnd_u32,
14303e69b50SDaniel Borkmann 	.gpl_only	= false,
14403e69b50SDaniel Borkmann 	.ret_type	= RET_INTEGER,
14503e69b50SDaniel Borkmann };
146c04167ceSDaniel Borkmann 
147f3694e00SDaniel Borkmann BPF_CALL_0(bpf_get_smp_processor_id)
148c04167ceSDaniel Borkmann {
14980b48c44SDaniel Borkmann 	return smp_processor_id();
150c04167ceSDaniel Borkmann }
151c04167ceSDaniel Borkmann 
152c04167ceSDaniel Borkmann const struct bpf_func_proto bpf_get_smp_processor_id_proto = {
153c04167ceSDaniel Borkmann 	.func		= bpf_get_smp_processor_id,
154c04167ceSDaniel Borkmann 	.gpl_only	= false,
155c04167ceSDaniel Borkmann 	.ret_type	= RET_INTEGER,
156c04167ceSDaniel Borkmann };
15717ca8cbfSDaniel Borkmann 
1582d0e30c3SDaniel Borkmann BPF_CALL_0(bpf_get_numa_node_id)
1592d0e30c3SDaniel Borkmann {
1602d0e30c3SDaniel Borkmann 	return numa_node_id();
1612d0e30c3SDaniel Borkmann }
1622d0e30c3SDaniel Borkmann 
1632d0e30c3SDaniel Borkmann const struct bpf_func_proto bpf_get_numa_node_id_proto = {
1642d0e30c3SDaniel Borkmann 	.func		= bpf_get_numa_node_id,
1652d0e30c3SDaniel Borkmann 	.gpl_only	= false,
1662d0e30c3SDaniel Borkmann 	.ret_type	= RET_INTEGER,
1672d0e30c3SDaniel Borkmann };
1682d0e30c3SDaniel Borkmann 
169f3694e00SDaniel Borkmann BPF_CALL_0(bpf_ktime_get_ns)
17017ca8cbfSDaniel Borkmann {
17117ca8cbfSDaniel Borkmann 	/* NMI safe access to clock monotonic */
17217ca8cbfSDaniel Borkmann 	return ktime_get_mono_fast_ns();
17317ca8cbfSDaniel Borkmann }
17417ca8cbfSDaniel Borkmann 
17517ca8cbfSDaniel Borkmann const struct bpf_func_proto bpf_ktime_get_ns_proto = {
17617ca8cbfSDaniel Borkmann 	.func		= bpf_ktime_get_ns,
177082b57e3SMaciej Żenczykowski 	.gpl_only	= false,
17817ca8cbfSDaniel Borkmann 	.ret_type	= RET_INTEGER,
17917ca8cbfSDaniel Borkmann };
180ffeedafbSAlexei Starovoitov 
18171d19214SMaciej Żenczykowski BPF_CALL_0(bpf_ktime_get_boot_ns)
18271d19214SMaciej Żenczykowski {
18371d19214SMaciej Żenczykowski 	/* NMI safe access to clock boottime */
18471d19214SMaciej Żenczykowski 	return ktime_get_boot_fast_ns();
18571d19214SMaciej Żenczykowski }
18671d19214SMaciej Żenczykowski 
18771d19214SMaciej Żenczykowski const struct bpf_func_proto bpf_ktime_get_boot_ns_proto = {
18871d19214SMaciej Żenczykowski 	.func		= bpf_ktime_get_boot_ns,
18971d19214SMaciej Żenczykowski 	.gpl_only	= false,
19071d19214SMaciej Żenczykowski 	.ret_type	= RET_INTEGER,
19171d19214SMaciej Żenczykowski };
19271d19214SMaciej Żenczykowski 
193d0551261SDmitrii Banshchikov BPF_CALL_0(bpf_ktime_get_coarse_ns)
194d0551261SDmitrii Banshchikov {
195d0551261SDmitrii Banshchikov 	return ktime_get_coarse_ns();
196d0551261SDmitrii Banshchikov }
197d0551261SDmitrii Banshchikov 
198d0551261SDmitrii Banshchikov const struct bpf_func_proto bpf_ktime_get_coarse_ns_proto = {
199d0551261SDmitrii Banshchikov 	.func		= bpf_ktime_get_coarse_ns,
200d0551261SDmitrii Banshchikov 	.gpl_only	= false,
201d0551261SDmitrii Banshchikov 	.ret_type	= RET_INTEGER,
202d0551261SDmitrii Banshchikov };
203d0551261SDmitrii Banshchikov 
204c8996c98SJesper Dangaard Brouer BPF_CALL_0(bpf_ktime_get_tai_ns)
205c8996c98SJesper Dangaard Brouer {
206c8996c98SJesper Dangaard Brouer 	/* NMI safe access to clock tai */
207c8996c98SJesper Dangaard Brouer 	return ktime_get_tai_fast_ns();
208c8996c98SJesper Dangaard Brouer }
209c8996c98SJesper Dangaard Brouer 
210c8996c98SJesper Dangaard Brouer const struct bpf_func_proto bpf_ktime_get_tai_ns_proto = {
211c8996c98SJesper Dangaard Brouer 	.func		= bpf_ktime_get_tai_ns,
212c8996c98SJesper Dangaard Brouer 	.gpl_only	= false,
213c8996c98SJesper Dangaard Brouer 	.ret_type	= RET_INTEGER,
214c8996c98SJesper Dangaard Brouer };
215c8996c98SJesper Dangaard Brouer 
216f3694e00SDaniel Borkmann BPF_CALL_0(bpf_get_current_pid_tgid)
217ffeedafbSAlexei Starovoitov {
218ffeedafbSAlexei Starovoitov 	struct task_struct *task = current;
219ffeedafbSAlexei Starovoitov 
2206088b582SDaniel Borkmann 	if (unlikely(!task))
221ffeedafbSAlexei Starovoitov 		return -EINVAL;
222ffeedafbSAlexei Starovoitov 
223ffeedafbSAlexei Starovoitov 	return (u64) task->tgid << 32 | task->pid;
224ffeedafbSAlexei Starovoitov }
225ffeedafbSAlexei Starovoitov 
226ffeedafbSAlexei Starovoitov const struct bpf_func_proto bpf_get_current_pid_tgid_proto = {
227ffeedafbSAlexei Starovoitov 	.func		= bpf_get_current_pid_tgid,
228ffeedafbSAlexei Starovoitov 	.gpl_only	= false,
229ffeedafbSAlexei Starovoitov 	.ret_type	= RET_INTEGER,
230ffeedafbSAlexei Starovoitov };
231ffeedafbSAlexei Starovoitov 
232f3694e00SDaniel Borkmann BPF_CALL_0(bpf_get_current_uid_gid)
233ffeedafbSAlexei Starovoitov {
234ffeedafbSAlexei Starovoitov 	struct task_struct *task = current;
235ffeedafbSAlexei Starovoitov 	kuid_t uid;
236ffeedafbSAlexei Starovoitov 	kgid_t gid;
237ffeedafbSAlexei Starovoitov 
2386088b582SDaniel Borkmann 	if (unlikely(!task))
239ffeedafbSAlexei Starovoitov 		return -EINVAL;
240ffeedafbSAlexei Starovoitov 
241ffeedafbSAlexei Starovoitov 	current_uid_gid(&uid, &gid);
242ffeedafbSAlexei Starovoitov 	return (u64) from_kgid(&init_user_ns, gid) << 32 |
243ffeedafbSAlexei Starovoitov 		     from_kuid(&init_user_ns, uid);
244ffeedafbSAlexei Starovoitov }
245ffeedafbSAlexei Starovoitov 
246ffeedafbSAlexei Starovoitov const struct bpf_func_proto bpf_get_current_uid_gid_proto = {
247ffeedafbSAlexei Starovoitov 	.func		= bpf_get_current_uid_gid,
248ffeedafbSAlexei Starovoitov 	.gpl_only	= false,
249ffeedafbSAlexei Starovoitov 	.ret_type	= RET_INTEGER,
250ffeedafbSAlexei Starovoitov };
251ffeedafbSAlexei Starovoitov 
252f3694e00SDaniel Borkmann BPF_CALL_2(bpf_get_current_comm, char *, buf, u32, size)
253ffeedafbSAlexei Starovoitov {
254ffeedafbSAlexei Starovoitov 	struct task_struct *task = current;
255ffeedafbSAlexei Starovoitov 
256074f528eSDaniel Borkmann 	if (unlikely(!task))
257074f528eSDaniel Borkmann 		goto err_clear;
258ffeedafbSAlexei Starovoitov 
25903b9c7faSYuntao Wang 	/* Verifier guarantees that size > 0 */
26003b9c7faSYuntao Wang 	strscpy(buf, task->comm, size);
261ffeedafbSAlexei Starovoitov 	return 0;
262074f528eSDaniel Borkmann err_clear:
263074f528eSDaniel Borkmann 	memset(buf, 0, size);
264074f528eSDaniel Borkmann 	return -EINVAL;
265ffeedafbSAlexei Starovoitov }
266ffeedafbSAlexei Starovoitov 
267ffeedafbSAlexei Starovoitov const struct bpf_func_proto bpf_get_current_comm_proto = {
268ffeedafbSAlexei Starovoitov 	.func		= bpf_get_current_comm,
269ffeedafbSAlexei Starovoitov 	.gpl_only	= false,
270ffeedafbSAlexei Starovoitov 	.ret_type	= RET_INTEGER,
27139f19ebbSAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
27239f19ebbSAlexei Starovoitov 	.arg2_type	= ARG_CONST_SIZE,
273ffeedafbSAlexei Starovoitov };
274bf6fa2c8SYonghong Song 
275d83525caSAlexei Starovoitov #if defined(CONFIG_QUEUED_SPINLOCKS) || defined(CONFIG_BPF_ARCH_SPINLOCK)
276d83525caSAlexei Starovoitov 
277d83525caSAlexei Starovoitov static inline void __bpf_spin_lock(struct bpf_spin_lock *lock)
278d83525caSAlexei Starovoitov {
279d83525caSAlexei Starovoitov 	arch_spinlock_t *l = (void *)lock;
280d83525caSAlexei Starovoitov 	union {
281d83525caSAlexei Starovoitov 		__u32 val;
282d83525caSAlexei Starovoitov 		arch_spinlock_t lock;
283d83525caSAlexei Starovoitov 	} u = { .lock = __ARCH_SPIN_LOCK_UNLOCKED };
284d83525caSAlexei Starovoitov 
285d83525caSAlexei Starovoitov 	compiletime_assert(u.val == 0, "__ARCH_SPIN_LOCK_UNLOCKED not 0");
286d83525caSAlexei Starovoitov 	BUILD_BUG_ON(sizeof(*l) != sizeof(__u32));
287d83525caSAlexei Starovoitov 	BUILD_BUG_ON(sizeof(*lock) != sizeof(__u32));
288d83525caSAlexei Starovoitov 	arch_spin_lock(l);
289d83525caSAlexei Starovoitov }
290d83525caSAlexei Starovoitov 
291d83525caSAlexei Starovoitov static inline void __bpf_spin_unlock(struct bpf_spin_lock *lock)
292d83525caSAlexei Starovoitov {
293d83525caSAlexei Starovoitov 	arch_spinlock_t *l = (void *)lock;
294d83525caSAlexei Starovoitov 
295d83525caSAlexei Starovoitov 	arch_spin_unlock(l);
296d83525caSAlexei Starovoitov }
297d83525caSAlexei Starovoitov 
298d83525caSAlexei Starovoitov #else
299d83525caSAlexei Starovoitov 
300d83525caSAlexei Starovoitov static inline void __bpf_spin_lock(struct bpf_spin_lock *lock)
301d83525caSAlexei Starovoitov {
302d83525caSAlexei Starovoitov 	atomic_t *l = (void *)lock;
303d83525caSAlexei Starovoitov 
304d83525caSAlexei Starovoitov 	BUILD_BUG_ON(sizeof(*l) != sizeof(*lock));
305d83525caSAlexei Starovoitov 	do {
306d83525caSAlexei Starovoitov 		atomic_cond_read_relaxed(l, !VAL);
307d83525caSAlexei Starovoitov 	} while (atomic_xchg(l, 1));
308d83525caSAlexei Starovoitov }
309d83525caSAlexei Starovoitov 
310d83525caSAlexei Starovoitov static inline void __bpf_spin_unlock(struct bpf_spin_lock *lock)
311d83525caSAlexei Starovoitov {
312d83525caSAlexei Starovoitov 	atomic_t *l = (void *)lock;
313d83525caSAlexei Starovoitov 
314d83525caSAlexei Starovoitov 	atomic_set_release(l, 0);
315d83525caSAlexei Starovoitov }
316d83525caSAlexei Starovoitov 
317d83525caSAlexei Starovoitov #endif
318d83525caSAlexei Starovoitov 
319d83525caSAlexei Starovoitov static DEFINE_PER_CPU(unsigned long, irqsave_flags);
320d83525caSAlexei Starovoitov 
321c1b3fed3SAlexei Starovoitov static inline void __bpf_spin_lock_irqsave(struct bpf_spin_lock *lock)
322d83525caSAlexei Starovoitov {
323d83525caSAlexei Starovoitov 	unsigned long flags;
324d83525caSAlexei Starovoitov 
325d83525caSAlexei Starovoitov 	local_irq_save(flags);
326d83525caSAlexei Starovoitov 	__bpf_spin_lock(lock);
327d83525caSAlexei Starovoitov 	__this_cpu_write(irqsave_flags, flags);
328c1b3fed3SAlexei Starovoitov }
329c1b3fed3SAlexei Starovoitov 
330c1b3fed3SAlexei Starovoitov notrace BPF_CALL_1(bpf_spin_lock, struct bpf_spin_lock *, lock)
331c1b3fed3SAlexei Starovoitov {
332c1b3fed3SAlexei Starovoitov 	__bpf_spin_lock_irqsave(lock);
333d83525caSAlexei Starovoitov 	return 0;
334d83525caSAlexei Starovoitov }
335d83525caSAlexei Starovoitov 
336d83525caSAlexei Starovoitov const struct bpf_func_proto bpf_spin_lock_proto = {
337d83525caSAlexei Starovoitov 	.func		= bpf_spin_lock,
338d83525caSAlexei Starovoitov 	.gpl_only	= false,
339d83525caSAlexei Starovoitov 	.ret_type	= RET_VOID,
340d83525caSAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_SPIN_LOCK,
3414e814da0SKumar Kartikeya Dwivedi 	.arg1_btf_id    = BPF_PTR_POISON,
342d83525caSAlexei Starovoitov };
343d83525caSAlexei Starovoitov 
344c1b3fed3SAlexei Starovoitov static inline void __bpf_spin_unlock_irqrestore(struct bpf_spin_lock *lock)
345d83525caSAlexei Starovoitov {
346d83525caSAlexei Starovoitov 	unsigned long flags;
347d83525caSAlexei Starovoitov 
348d83525caSAlexei Starovoitov 	flags = __this_cpu_read(irqsave_flags);
349d83525caSAlexei Starovoitov 	__bpf_spin_unlock(lock);
350d83525caSAlexei Starovoitov 	local_irq_restore(flags);
351c1b3fed3SAlexei Starovoitov }
352c1b3fed3SAlexei Starovoitov 
353c1b3fed3SAlexei Starovoitov notrace BPF_CALL_1(bpf_spin_unlock, struct bpf_spin_lock *, lock)
354c1b3fed3SAlexei Starovoitov {
355c1b3fed3SAlexei Starovoitov 	__bpf_spin_unlock_irqrestore(lock);
356d83525caSAlexei Starovoitov 	return 0;
357d83525caSAlexei Starovoitov }
358d83525caSAlexei Starovoitov 
359d83525caSAlexei Starovoitov const struct bpf_func_proto bpf_spin_unlock_proto = {
360d83525caSAlexei Starovoitov 	.func		= bpf_spin_unlock,
361d83525caSAlexei Starovoitov 	.gpl_only	= false,
362d83525caSAlexei Starovoitov 	.ret_type	= RET_VOID,
363d83525caSAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_SPIN_LOCK,
3644e814da0SKumar Kartikeya Dwivedi 	.arg1_btf_id    = BPF_PTR_POISON,
365d83525caSAlexei Starovoitov };
366d83525caSAlexei Starovoitov 
36796049f3aSAlexei Starovoitov void copy_map_value_locked(struct bpf_map *map, void *dst, void *src,
36896049f3aSAlexei Starovoitov 			   bool lock_src)
36996049f3aSAlexei Starovoitov {
37096049f3aSAlexei Starovoitov 	struct bpf_spin_lock *lock;
37196049f3aSAlexei Starovoitov 
37296049f3aSAlexei Starovoitov 	if (lock_src)
373db559117SKumar Kartikeya Dwivedi 		lock = src + map->record->spin_lock_off;
37496049f3aSAlexei Starovoitov 	else
375db559117SKumar Kartikeya Dwivedi 		lock = dst + map->record->spin_lock_off;
37696049f3aSAlexei Starovoitov 	preempt_disable();
377c1b3fed3SAlexei Starovoitov 	__bpf_spin_lock_irqsave(lock);
37896049f3aSAlexei Starovoitov 	copy_map_value(map, dst, src);
379c1b3fed3SAlexei Starovoitov 	__bpf_spin_unlock_irqrestore(lock);
38096049f3aSAlexei Starovoitov 	preempt_enable();
38196049f3aSAlexei Starovoitov }
38296049f3aSAlexei Starovoitov 
3835576b991SMartin KaFai Lau BPF_CALL_0(bpf_jiffies64)
3845576b991SMartin KaFai Lau {
3855576b991SMartin KaFai Lau 	return get_jiffies_64();
3865576b991SMartin KaFai Lau }
3875576b991SMartin KaFai Lau 
3885576b991SMartin KaFai Lau const struct bpf_func_proto bpf_jiffies64_proto = {
3895576b991SMartin KaFai Lau 	.func		= bpf_jiffies64,
3905576b991SMartin KaFai Lau 	.gpl_only	= false,
3915576b991SMartin KaFai Lau 	.ret_type	= RET_INTEGER,
3925576b991SMartin KaFai Lau };
3935576b991SMartin KaFai Lau 
394bf6fa2c8SYonghong Song #ifdef CONFIG_CGROUPS
395bf6fa2c8SYonghong Song BPF_CALL_0(bpf_get_current_cgroup_id)
396bf6fa2c8SYonghong Song {
3972d3a1e36SYonghong Song 	struct cgroup *cgrp;
3982d3a1e36SYonghong Song 	u64 cgrp_id;
399bf6fa2c8SYonghong Song 
4002d3a1e36SYonghong Song 	rcu_read_lock();
4012d3a1e36SYonghong Song 	cgrp = task_dfl_cgroup(current);
4022d3a1e36SYonghong Song 	cgrp_id = cgroup_id(cgrp);
4032d3a1e36SYonghong Song 	rcu_read_unlock();
4042d3a1e36SYonghong Song 
4052d3a1e36SYonghong Song 	return cgrp_id;
406bf6fa2c8SYonghong Song }
407bf6fa2c8SYonghong Song 
408bf6fa2c8SYonghong Song const struct bpf_func_proto bpf_get_current_cgroup_id_proto = {
409bf6fa2c8SYonghong Song 	.func		= bpf_get_current_cgroup_id,
410bf6fa2c8SYonghong Song 	.gpl_only	= false,
411bf6fa2c8SYonghong Song 	.ret_type	= RET_INTEGER,
412bf6fa2c8SYonghong Song };
413cd339431SRoman Gushchin 
4140f09abd1SDaniel Borkmann BPF_CALL_1(bpf_get_current_ancestor_cgroup_id, int, ancestor_level)
4150f09abd1SDaniel Borkmann {
4162d3a1e36SYonghong Song 	struct cgroup *cgrp;
4170f09abd1SDaniel Borkmann 	struct cgroup *ancestor;
4182d3a1e36SYonghong Song 	u64 cgrp_id;
4190f09abd1SDaniel Borkmann 
4202d3a1e36SYonghong Song 	rcu_read_lock();
4212d3a1e36SYonghong Song 	cgrp = task_dfl_cgroup(current);
4220f09abd1SDaniel Borkmann 	ancestor = cgroup_ancestor(cgrp, ancestor_level);
4232d3a1e36SYonghong Song 	cgrp_id = ancestor ? cgroup_id(ancestor) : 0;
4242d3a1e36SYonghong Song 	rcu_read_unlock();
4252d3a1e36SYonghong Song 
4262d3a1e36SYonghong Song 	return cgrp_id;
4270f09abd1SDaniel Borkmann }
4280f09abd1SDaniel Borkmann 
4290f09abd1SDaniel Borkmann const struct bpf_func_proto bpf_get_current_ancestor_cgroup_id_proto = {
4300f09abd1SDaniel Borkmann 	.func		= bpf_get_current_ancestor_cgroup_id,
4310f09abd1SDaniel Borkmann 	.gpl_only	= false,
4320f09abd1SDaniel Borkmann 	.ret_type	= RET_INTEGER,
4330f09abd1SDaniel Borkmann 	.arg1_type	= ARG_ANYTHING,
4340f09abd1SDaniel Borkmann };
4358a67f2deSStanislav Fomichev #endif /* CONFIG_CGROUPS */
4360f09abd1SDaniel Borkmann 
437d7a4cb9bSAndrey Ignatov #define BPF_STRTOX_BASE_MASK 0x1F
438d7a4cb9bSAndrey Ignatov 
439d7a4cb9bSAndrey Ignatov static int __bpf_strtoull(const char *buf, size_t buf_len, u64 flags,
440d7a4cb9bSAndrey Ignatov 			  unsigned long long *res, bool *is_negative)
441d7a4cb9bSAndrey Ignatov {
442d7a4cb9bSAndrey Ignatov 	unsigned int base = flags & BPF_STRTOX_BASE_MASK;
443d7a4cb9bSAndrey Ignatov 	const char *cur_buf = buf;
444d7a4cb9bSAndrey Ignatov 	size_t cur_len = buf_len;
445d7a4cb9bSAndrey Ignatov 	unsigned int consumed;
446d7a4cb9bSAndrey Ignatov 	size_t val_len;
447d7a4cb9bSAndrey Ignatov 	char str[64];
448d7a4cb9bSAndrey Ignatov 
449d7a4cb9bSAndrey Ignatov 	if (!buf || !buf_len || !res || !is_negative)
450d7a4cb9bSAndrey Ignatov 		return -EINVAL;
451d7a4cb9bSAndrey Ignatov 
452d7a4cb9bSAndrey Ignatov 	if (base != 0 && base != 8 && base != 10 && base != 16)
453d7a4cb9bSAndrey Ignatov 		return -EINVAL;
454d7a4cb9bSAndrey Ignatov 
455d7a4cb9bSAndrey Ignatov 	if (flags & ~BPF_STRTOX_BASE_MASK)
456d7a4cb9bSAndrey Ignatov 		return -EINVAL;
457d7a4cb9bSAndrey Ignatov 
458d7a4cb9bSAndrey Ignatov 	while (cur_buf < buf + buf_len && isspace(*cur_buf))
459d7a4cb9bSAndrey Ignatov 		++cur_buf;
460d7a4cb9bSAndrey Ignatov 
461d7a4cb9bSAndrey Ignatov 	*is_negative = (cur_buf < buf + buf_len && *cur_buf == '-');
462d7a4cb9bSAndrey Ignatov 	if (*is_negative)
463d7a4cb9bSAndrey Ignatov 		++cur_buf;
464d7a4cb9bSAndrey Ignatov 
465d7a4cb9bSAndrey Ignatov 	consumed = cur_buf - buf;
466d7a4cb9bSAndrey Ignatov 	cur_len -= consumed;
467d7a4cb9bSAndrey Ignatov 	if (!cur_len)
468d7a4cb9bSAndrey Ignatov 		return -EINVAL;
469d7a4cb9bSAndrey Ignatov 
470d7a4cb9bSAndrey Ignatov 	cur_len = min(cur_len, sizeof(str) - 1);
471d7a4cb9bSAndrey Ignatov 	memcpy(str, cur_buf, cur_len);
472d7a4cb9bSAndrey Ignatov 	str[cur_len] = '\0';
473d7a4cb9bSAndrey Ignatov 	cur_buf = str;
474d7a4cb9bSAndrey Ignatov 
475d7a4cb9bSAndrey Ignatov 	cur_buf = _parse_integer_fixup_radix(cur_buf, &base);
476d7a4cb9bSAndrey Ignatov 	val_len = _parse_integer(cur_buf, base, res);
477d7a4cb9bSAndrey Ignatov 
478d7a4cb9bSAndrey Ignatov 	if (val_len & KSTRTOX_OVERFLOW)
479d7a4cb9bSAndrey Ignatov 		return -ERANGE;
480d7a4cb9bSAndrey Ignatov 
481d7a4cb9bSAndrey Ignatov 	if (val_len == 0)
482d7a4cb9bSAndrey Ignatov 		return -EINVAL;
483d7a4cb9bSAndrey Ignatov 
484d7a4cb9bSAndrey Ignatov 	cur_buf += val_len;
485d7a4cb9bSAndrey Ignatov 	consumed += cur_buf - str;
486d7a4cb9bSAndrey Ignatov 
487d7a4cb9bSAndrey Ignatov 	return consumed;
488d7a4cb9bSAndrey Ignatov }
489d7a4cb9bSAndrey Ignatov 
490d7a4cb9bSAndrey Ignatov static int __bpf_strtoll(const char *buf, size_t buf_len, u64 flags,
491d7a4cb9bSAndrey Ignatov 			 long long *res)
492d7a4cb9bSAndrey Ignatov {
493d7a4cb9bSAndrey Ignatov 	unsigned long long _res;
494d7a4cb9bSAndrey Ignatov 	bool is_negative;
495d7a4cb9bSAndrey Ignatov 	int err;
496d7a4cb9bSAndrey Ignatov 
497d7a4cb9bSAndrey Ignatov 	err = __bpf_strtoull(buf, buf_len, flags, &_res, &is_negative);
498d7a4cb9bSAndrey Ignatov 	if (err < 0)
499d7a4cb9bSAndrey Ignatov 		return err;
500d7a4cb9bSAndrey Ignatov 	if (is_negative) {
501d7a4cb9bSAndrey Ignatov 		if ((long long)-_res > 0)
502d7a4cb9bSAndrey Ignatov 			return -ERANGE;
503d7a4cb9bSAndrey Ignatov 		*res = -_res;
504d7a4cb9bSAndrey Ignatov 	} else {
505d7a4cb9bSAndrey Ignatov 		if ((long long)_res < 0)
506d7a4cb9bSAndrey Ignatov 			return -ERANGE;
507d7a4cb9bSAndrey Ignatov 		*res = _res;
508d7a4cb9bSAndrey Ignatov 	}
509d7a4cb9bSAndrey Ignatov 	return err;
510d7a4cb9bSAndrey Ignatov }
511d7a4cb9bSAndrey Ignatov 
512d7a4cb9bSAndrey Ignatov BPF_CALL_4(bpf_strtol, const char *, buf, size_t, buf_len, u64, flags,
513d7a4cb9bSAndrey Ignatov 	   long *, res)
514d7a4cb9bSAndrey Ignatov {
515d7a4cb9bSAndrey Ignatov 	long long _res;
516d7a4cb9bSAndrey Ignatov 	int err;
517d7a4cb9bSAndrey Ignatov 
518d7a4cb9bSAndrey Ignatov 	err = __bpf_strtoll(buf, buf_len, flags, &_res);
519d7a4cb9bSAndrey Ignatov 	if (err < 0)
520d7a4cb9bSAndrey Ignatov 		return err;
521d7a4cb9bSAndrey Ignatov 	if (_res != (long)_res)
522d7a4cb9bSAndrey Ignatov 		return -ERANGE;
523d7a4cb9bSAndrey Ignatov 	*res = _res;
524d7a4cb9bSAndrey Ignatov 	return err;
525d7a4cb9bSAndrey Ignatov }
526d7a4cb9bSAndrey Ignatov 
527d7a4cb9bSAndrey Ignatov const struct bpf_func_proto bpf_strtol_proto = {
528d7a4cb9bSAndrey Ignatov 	.func		= bpf_strtol,
529d7a4cb9bSAndrey Ignatov 	.gpl_only	= false,
530d7a4cb9bSAndrey Ignatov 	.ret_type	= RET_INTEGER,
531216e3cd2SHao Luo 	.arg1_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
532d7a4cb9bSAndrey Ignatov 	.arg2_type	= ARG_CONST_SIZE,
533d7a4cb9bSAndrey Ignatov 	.arg3_type	= ARG_ANYTHING,
534d7a4cb9bSAndrey Ignatov 	.arg4_type	= ARG_PTR_TO_LONG,
535d7a4cb9bSAndrey Ignatov };
536d7a4cb9bSAndrey Ignatov 
537d7a4cb9bSAndrey Ignatov BPF_CALL_4(bpf_strtoul, const char *, buf, size_t, buf_len, u64, flags,
538d7a4cb9bSAndrey Ignatov 	   unsigned long *, res)
539d7a4cb9bSAndrey Ignatov {
540d7a4cb9bSAndrey Ignatov 	unsigned long long _res;
541d7a4cb9bSAndrey Ignatov 	bool is_negative;
542d7a4cb9bSAndrey Ignatov 	int err;
543d7a4cb9bSAndrey Ignatov 
544d7a4cb9bSAndrey Ignatov 	err = __bpf_strtoull(buf, buf_len, flags, &_res, &is_negative);
545d7a4cb9bSAndrey Ignatov 	if (err < 0)
546d7a4cb9bSAndrey Ignatov 		return err;
547d7a4cb9bSAndrey Ignatov 	if (is_negative)
548d7a4cb9bSAndrey Ignatov 		return -EINVAL;
549d7a4cb9bSAndrey Ignatov 	if (_res != (unsigned long)_res)
550d7a4cb9bSAndrey Ignatov 		return -ERANGE;
551d7a4cb9bSAndrey Ignatov 	*res = _res;
552d7a4cb9bSAndrey Ignatov 	return err;
553d7a4cb9bSAndrey Ignatov }
554d7a4cb9bSAndrey Ignatov 
555d7a4cb9bSAndrey Ignatov const struct bpf_func_proto bpf_strtoul_proto = {
556d7a4cb9bSAndrey Ignatov 	.func		= bpf_strtoul,
557d7a4cb9bSAndrey Ignatov 	.gpl_only	= false,
558d7a4cb9bSAndrey Ignatov 	.ret_type	= RET_INTEGER,
559216e3cd2SHao Luo 	.arg1_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
560d7a4cb9bSAndrey Ignatov 	.arg2_type	= ARG_CONST_SIZE,
561d7a4cb9bSAndrey Ignatov 	.arg3_type	= ARG_ANYTHING,
562d7a4cb9bSAndrey Ignatov 	.arg4_type	= ARG_PTR_TO_LONG,
563d7a4cb9bSAndrey Ignatov };
564b4490c5cSCarlos Neira 
565c5fb1993SHou Tao BPF_CALL_3(bpf_strncmp, const char *, s1, u32, s1_sz, const char *, s2)
566c5fb1993SHou Tao {
567c5fb1993SHou Tao 	return strncmp(s1, s2, s1_sz);
568c5fb1993SHou Tao }
569c5fb1993SHou Tao 
570dc368e1cSJoanne Koong static const struct bpf_func_proto bpf_strncmp_proto = {
571c5fb1993SHou Tao 	.func		= bpf_strncmp,
572c5fb1993SHou Tao 	.gpl_only	= false,
573c5fb1993SHou Tao 	.ret_type	= RET_INTEGER,
574c5fb1993SHou Tao 	.arg1_type	= ARG_PTR_TO_MEM,
575c5fb1993SHou Tao 	.arg2_type	= ARG_CONST_SIZE,
576c5fb1993SHou Tao 	.arg3_type	= ARG_PTR_TO_CONST_STR,
577c5fb1993SHou Tao };
578c5fb1993SHou Tao 
579b4490c5cSCarlos Neira BPF_CALL_4(bpf_get_ns_current_pid_tgid, u64, dev, u64, ino,
580b4490c5cSCarlos Neira 	   struct bpf_pidns_info *, nsdata, u32, size)
581b4490c5cSCarlos Neira {
582b4490c5cSCarlos Neira 	struct task_struct *task = current;
583b4490c5cSCarlos Neira 	struct pid_namespace *pidns;
584b4490c5cSCarlos Neira 	int err = -EINVAL;
585b4490c5cSCarlos Neira 
586b4490c5cSCarlos Neira 	if (unlikely(size != sizeof(struct bpf_pidns_info)))
587b4490c5cSCarlos Neira 		goto clear;
588b4490c5cSCarlos Neira 
589b4490c5cSCarlos Neira 	if (unlikely((u64)(dev_t)dev != dev))
590b4490c5cSCarlos Neira 		goto clear;
591b4490c5cSCarlos Neira 
592b4490c5cSCarlos Neira 	if (unlikely(!task))
593b4490c5cSCarlos Neira 		goto clear;
594b4490c5cSCarlos Neira 
595b4490c5cSCarlos Neira 	pidns = task_active_pid_ns(task);
596b4490c5cSCarlos Neira 	if (unlikely(!pidns)) {
597b4490c5cSCarlos Neira 		err = -ENOENT;
598b4490c5cSCarlos Neira 		goto clear;
599b4490c5cSCarlos Neira 	}
600b4490c5cSCarlos Neira 
601b4490c5cSCarlos Neira 	if (!ns_match(&pidns->ns, (dev_t)dev, ino))
602b4490c5cSCarlos Neira 		goto clear;
603b4490c5cSCarlos Neira 
604b4490c5cSCarlos Neira 	nsdata->pid = task_pid_nr_ns(task, pidns);
605b4490c5cSCarlos Neira 	nsdata->tgid = task_tgid_nr_ns(task, pidns);
606b4490c5cSCarlos Neira 	return 0;
607b4490c5cSCarlos Neira clear:
608b4490c5cSCarlos Neira 	memset((void *)nsdata, 0, (size_t) size);
609b4490c5cSCarlos Neira 	return err;
610b4490c5cSCarlos Neira }
611b4490c5cSCarlos Neira 
612b4490c5cSCarlos Neira const struct bpf_func_proto bpf_get_ns_current_pid_tgid_proto = {
613b4490c5cSCarlos Neira 	.func		= bpf_get_ns_current_pid_tgid,
614b4490c5cSCarlos Neira 	.gpl_only	= false,
615b4490c5cSCarlos Neira 	.ret_type	= RET_INTEGER,
616b4490c5cSCarlos Neira 	.arg1_type	= ARG_ANYTHING,
617b4490c5cSCarlos Neira 	.arg2_type	= ARG_ANYTHING,
618b4490c5cSCarlos Neira 	.arg3_type      = ARG_PTR_TO_UNINIT_MEM,
619b4490c5cSCarlos Neira 	.arg4_type      = ARG_CONST_SIZE,
620b4490c5cSCarlos Neira };
6216890896bSStanislav Fomichev 
6226890896bSStanislav Fomichev static const struct bpf_func_proto bpf_get_raw_smp_processor_id_proto = {
6236890896bSStanislav Fomichev 	.func		= bpf_get_raw_cpu_id,
6246890896bSStanislav Fomichev 	.gpl_only	= false,
6256890896bSStanislav Fomichev 	.ret_type	= RET_INTEGER,
6266890896bSStanislav Fomichev };
6276890896bSStanislav Fomichev 
6286890896bSStanislav Fomichev BPF_CALL_5(bpf_event_output_data, void *, ctx, struct bpf_map *, map,
6296890896bSStanislav Fomichev 	   u64, flags, void *, data, u64, size)
6306890896bSStanislav Fomichev {
6316890896bSStanislav Fomichev 	if (unlikely(flags & ~(BPF_F_INDEX_MASK)))
6326890896bSStanislav Fomichev 		return -EINVAL;
6336890896bSStanislav Fomichev 
6346890896bSStanislav Fomichev 	return bpf_event_output(map, flags, data, size, NULL, 0, NULL);
6356890896bSStanislav Fomichev }
6366890896bSStanislav Fomichev 
6376890896bSStanislav Fomichev const struct bpf_func_proto bpf_event_output_data_proto =  {
6386890896bSStanislav Fomichev 	.func		= bpf_event_output_data,
6396890896bSStanislav Fomichev 	.gpl_only       = true,
6406890896bSStanislav Fomichev 	.ret_type       = RET_INTEGER,
6416890896bSStanislav Fomichev 	.arg1_type      = ARG_PTR_TO_CTX,
6426890896bSStanislav Fomichev 	.arg2_type      = ARG_CONST_MAP_PTR,
6436890896bSStanislav Fomichev 	.arg3_type      = ARG_ANYTHING,
644216e3cd2SHao Luo 	.arg4_type      = ARG_PTR_TO_MEM | MEM_RDONLY,
6456890896bSStanislav Fomichev 	.arg5_type      = ARG_CONST_SIZE_OR_ZERO,
6466890896bSStanislav Fomichev };
6476890896bSStanislav Fomichev 
64807be4c4aSAlexei Starovoitov BPF_CALL_3(bpf_copy_from_user, void *, dst, u32, size,
64907be4c4aSAlexei Starovoitov 	   const void __user *, user_ptr)
65007be4c4aSAlexei Starovoitov {
65107be4c4aSAlexei Starovoitov 	int ret = copy_from_user(dst, user_ptr, size);
65207be4c4aSAlexei Starovoitov 
65307be4c4aSAlexei Starovoitov 	if (unlikely(ret)) {
65407be4c4aSAlexei Starovoitov 		memset(dst, 0, size);
65507be4c4aSAlexei Starovoitov 		ret = -EFAULT;
65607be4c4aSAlexei Starovoitov 	}
65707be4c4aSAlexei Starovoitov 
65807be4c4aSAlexei Starovoitov 	return ret;
65907be4c4aSAlexei Starovoitov }
66007be4c4aSAlexei Starovoitov 
66107be4c4aSAlexei Starovoitov const struct bpf_func_proto bpf_copy_from_user_proto = {
66207be4c4aSAlexei Starovoitov 	.func		= bpf_copy_from_user,
66307be4c4aSAlexei Starovoitov 	.gpl_only	= false,
66407be4c4aSAlexei Starovoitov 	.ret_type	= RET_INTEGER,
66507be4c4aSAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
66607be4c4aSAlexei Starovoitov 	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
66707be4c4aSAlexei Starovoitov 	.arg3_type	= ARG_ANYTHING,
66807be4c4aSAlexei Starovoitov };
66907be4c4aSAlexei Starovoitov 
670376040e4SKenny Yu BPF_CALL_5(bpf_copy_from_user_task, void *, dst, u32, size,
671376040e4SKenny Yu 	   const void __user *, user_ptr, struct task_struct *, tsk, u64, flags)
672376040e4SKenny Yu {
673376040e4SKenny Yu 	int ret;
674376040e4SKenny Yu 
675376040e4SKenny Yu 	/* flags is not used yet */
676376040e4SKenny Yu 	if (unlikely(flags))
677376040e4SKenny Yu 		return -EINVAL;
678376040e4SKenny Yu 
679376040e4SKenny Yu 	if (unlikely(!size))
680376040e4SKenny Yu 		return 0;
681376040e4SKenny Yu 
682376040e4SKenny Yu 	ret = access_process_vm(tsk, (unsigned long)user_ptr, dst, size, 0);
683376040e4SKenny Yu 	if (ret == size)
684376040e4SKenny Yu 		return 0;
685376040e4SKenny Yu 
686376040e4SKenny Yu 	memset(dst, 0, size);
687376040e4SKenny Yu 	/* Return -EFAULT for partial read */
688376040e4SKenny Yu 	return ret < 0 ? ret : -EFAULT;
689376040e4SKenny Yu }
690376040e4SKenny Yu 
691376040e4SKenny Yu const struct bpf_func_proto bpf_copy_from_user_task_proto = {
692376040e4SKenny Yu 	.func		= bpf_copy_from_user_task,
6930407a65fSKenta Tada 	.gpl_only	= true,
694376040e4SKenny Yu 	.ret_type	= RET_INTEGER,
695376040e4SKenny Yu 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
696376040e4SKenny Yu 	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
697376040e4SKenny Yu 	.arg3_type	= ARG_ANYTHING,
698376040e4SKenny Yu 	.arg4_type	= ARG_PTR_TO_BTF_ID,
699376040e4SKenny Yu 	.arg4_btf_id	= &btf_tracing_ids[BTF_TRACING_TYPE_TASK],
700376040e4SKenny Yu 	.arg5_type	= ARG_ANYTHING
701376040e4SKenny Yu };
702376040e4SKenny Yu 
703eaa6bcb7SHao Luo BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu)
704eaa6bcb7SHao Luo {
705eaa6bcb7SHao Luo 	if (cpu >= nr_cpu_ids)
706eaa6bcb7SHao Luo 		return (unsigned long)NULL;
707eaa6bcb7SHao Luo 
708eaa6bcb7SHao Luo 	return (unsigned long)per_cpu_ptr((const void __percpu *)ptr, cpu);
709eaa6bcb7SHao Luo }
710eaa6bcb7SHao Luo 
711eaa6bcb7SHao Luo const struct bpf_func_proto bpf_per_cpu_ptr_proto = {
712eaa6bcb7SHao Luo 	.func		= bpf_per_cpu_ptr,
713eaa6bcb7SHao Luo 	.gpl_only	= false,
71434d3a78cSHao Luo 	.ret_type	= RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL | MEM_RDONLY,
715eaa6bcb7SHao Luo 	.arg1_type	= ARG_PTR_TO_PERCPU_BTF_ID,
716eaa6bcb7SHao Luo 	.arg2_type	= ARG_ANYTHING,
717eaa6bcb7SHao Luo };
718eaa6bcb7SHao Luo 
71963d9b80dSHao Luo BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr)
72063d9b80dSHao Luo {
72163d9b80dSHao Luo 	return (unsigned long)this_cpu_ptr((const void __percpu *)percpu_ptr);
72263d9b80dSHao Luo }
72363d9b80dSHao Luo 
72463d9b80dSHao Luo const struct bpf_func_proto bpf_this_cpu_ptr_proto = {
72563d9b80dSHao Luo 	.func		= bpf_this_cpu_ptr,
72663d9b80dSHao Luo 	.gpl_only	= false,
72734d3a78cSHao Luo 	.ret_type	= RET_PTR_TO_MEM_OR_BTF_ID | MEM_RDONLY,
72863d9b80dSHao Luo 	.arg1_type	= ARG_PTR_TO_PERCPU_BTF_ID,
72963d9b80dSHao Luo };
73063d9b80dSHao Luo 
731d9c9e4dbSFlorent Revest static int bpf_trace_copy_string(char *buf, void *unsafe_ptr, char fmt_ptype,
732d9c9e4dbSFlorent Revest 		size_t bufsz)
733d9c9e4dbSFlorent Revest {
734d9c9e4dbSFlorent Revest 	void __user *user_ptr = (__force void __user *)unsafe_ptr;
735d9c9e4dbSFlorent Revest 
736d9c9e4dbSFlorent Revest 	buf[0] = 0;
737d9c9e4dbSFlorent Revest 
738d9c9e4dbSFlorent Revest 	switch (fmt_ptype) {
739d9c9e4dbSFlorent Revest 	case 's':
740d9c9e4dbSFlorent Revest #ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
741d9c9e4dbSFlorent Revest 		if ((unsigned long)unsafe_ptr < TASK_SIZE)
742d9c9e4dbSFlorent Revest 			return strncpy_from_user_nofault(buf, user_ptr, bufsz);
743d9c9e4dbSFlorent Revest 		fallthrough;
744d9c9e4dbSFlorent Revest #endif
745d9c9e4dbSFlorent Revest 	case 'k':
746d9c9e4dbSFlorent Revest 		return strncpy_from_kernel_nofault(buf, unsafe_ptr, bufsz);
747d9c9e4dbSFlorent Revest 	case 'u':
748d9c9e4dbSFlorent Revest 		return strncpy_from_user_nofault(buf, user_ptr, bufsz);
749d9c9e4dbSFlorent Revest 	}
750d9c9e4dbSFlorent Revest 
751d9c9e4dbSFlorent Revest 	return -EINVAL;
752d9c9e4dbSFlorent Revest }
753d9c9e4dbSFlorent Revest 
7548afcc19fSFlorent Revest /* Per-cpu temp buffers used by printf-like helpers to store the bprintf binary
7558afcc19fSFlorent Revest  * arguments representation.
756d9c9e4dbSFlorent Revest  */
7578afcc19fSFlorent Revest #define MAX_BPRINTF_BUF_LEN	512
758d9c9e4dbSFlorent Revest 
759e2d5b2bbSFlorent Revest /* Support executing three nested bprintf helper calls on a given CPU */
7600af02eb2SFlorent Revest #define MAX_BPRINTF_NEST_LEVEL	3
761e2d5b2bbSFlorent Revest struct bpf_bprintf_buffers {
7620af02eb2SFlorent Revest 	char tmp_bufs[MAX_BPRINTF_NEST_LEVEL][MAX_BPRINTF_BUF_LEN];
763d9c9e4dbSFlorent Revest };
764e2d5b2bbSFlorent Revest static DEFINE_PER_CPU(struct bpf_bprintf_buffers, bpf_bprintf_bufs);
765e2d5b2bbSFlorent Revest static DEFINE_PER_CPU(int, bpf_bprintf_nest_level);
766d9c9e4dbSFlorent Revest 
767d9c9e4dbSFlorent Revest static int try_get_fmt_tmp_buf(char **tmp_buf)
768d9c9e4dbSFlorent Revest {
769e2d5b2bbSFlorent Revest 	struct bpf_bprintf_buffers *bufs;
770e2d5b2bbSFlorent Revest 	int nest_level;
771d9c9e4dbSFlorent Revest 
772d9c9e4dbSFlorent Revest 	preempt_disable();
773e2d5b2bbSFlorent Revest 	nest_level = this_cpu_inc_return(bpf_bprintf_nest_level);
7740af02eb2SFlorent Revest 	if (WARN_ON_ONCE(nest_level > MAX_BPRINTF_NEST_LEVEL)) {
775e2d5b2bbSFlorent Revest 		this_cpu_dec(bpf_bprintf_nest_level);
776d9c9e4dbSFlorent Revest 		preempt_enable();
777d9c9e4dbSFlorent Revest 		return -EBUSY;
778d9c9e4dbSFlorent Revest 	}
779e2d5b2bbSFlorent Revest 	bufs = this_cpu_ptr(&bpf_bprintf_bufs);
780e2d5b2bbSFlorent Revest 	*tmp_buf = bufs->tmp_bufs[nest_level - 1];
781d9c9e4dbSFlorent Revest 
782d9c9e4dbSFlorent Revest 	return 0;
783d9c9e4dbSFlorent Revest }
784d9c9e4dbSFlorent Revest 
78548cac3f4SFlorent Revest void bpf_bprintf_cleanup(void)
786d9c9e4dbSFlorent Revest {
787e2d5b2bbSFlorent Revest 	if (this_cpu_read(bpf_bprintf_nest_level)) {
788e2d5b2bbSFlorent Revest 		this_cpu_dec(bpf_bprintf_nest_level);
789d9c9e4dbSFlorent Revest 		preempt_enable();
790d9c9e4dbSFlorent Revest 	}
791d9c9e4dbSFlorent Revest }
792d9c9e4dbSFlorent Revest 
793d9c9e4dbSFlorent Revest /*
79448cac3f4SFlorent Revest  * bpf_bprintf_prepare - Generic pass on format strings for bprintf-like helpers
795d9c9e4dbSFlorent Revest  *
796d9c9e4dbSFlorent Revest  * Returns a negative value if fmt is an invalid format string or 0 otherwise.
797d9c9e4dbSFlorent Revest  *
798d9c9e4dbSFlorent Revest  * This can be used in two ways:
79948cac3f4SFlorent Revest  * - Format string verification only: when bin_args is NULL
800d9c9e4dbSFlorent Revest  * - Arguments preparation: in addition to the above verification, it writes in
80148cac3f4SFlorent Revest  *   bin_args a binary representation of arguments usable by bstr_printf where
80248cac3f4SFlorent Revest  *   pointers from BPF have been sanitized.
803d9c9e4dbSFlorent Revest  *
804d9c9e4dbSFlorent Revest  * In argument preparation mode, if 0 is returned, safe temporary buffers are
80548cac3f4SFlorent Revest  * allocated and bpf_bprintf_cleanup should be called to free them after use.
806d9c9e4dbSFlorent Revest  */
80748cac3f4SFlorent Revest int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args,
80848cac3f4SFlorent Revest 			u32 **bin_args, u32 num_args)
809d9c9e4dbSFlorent Revest {
81048cac3f4SFlorent Revest 	char *unsafe_ptr = NULL, *tmp_buf = NULL, *tmp_buf_end, *fmt_end;
81148cac3f4SFlorent Revest 	size_t sizeof_cur_arg, sizeof_cur_ip;
81248cac3f4SFlorent Revest 	int err, i, num_spec = 0;
813d9c9e4dbSFlorent Revest 	u64 cur_arg;
81448cac3f4SFlorent Revest 	char fmt_ptype, cur_ip[16], ip_spec[] = "%pXX";
815d9c9e4dbSFlorent Revest 
816d9c9e4dbSFlorent Revest 	fmt_end = strnchr(fmt, fmt_size, 0);
817d9c9e4dbSFlorent Revest 	if (!fmt_end)
818d9c9e4dbSFlorent Revest 		return -EINVAL;
819d9c9e4dbSFlorent Revest 	fmt_size = fmt_end - fmt;
820d9c9e4dbSFlorent Revest 
82148cac3f4SFlorent Revest 	if (bin_args) {
82248cac3f4SFlorent Revest 		if (num_args && try_get_fmt_tmp_buf(&tmp_buf))
82348cac3f4SFlorent Revest 			return -EBUSY;
82448cac3f4SFlorent Revest 
8258afcc19fSFlorent Revest 		tmp_buf_end = tmp_buf + MAX_BPRINTF_BUF_LEN;
82648cac3f4SFlorent Revest 		*bin_args = (u32 *)tmp_buf;
82748cac3f4SFlorent Revest 	}
82848cac3f4SFlorent Revest 
829d9c9e4dbSFlorent Revest 	for (i = 0; i < fmt_size; i++) {
830d9c9e4dbSFlorent Revest 		if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) {
831d9c9e4dbSFlorent Revest 			err = -EINVAL;
83248cac3f4SFlorent Revest 			goto out;
833d9c9e4dbSFlorent Revest 		}
834d9c9e4dbSFlorent Revest 
835d9c9e4dbSFlorent Revest 		if (fmt[i] != '%')
836d9c9e4dbSFlorent Revest 			continue;
837d9c9e4dbSFlorent Revest 
838d9c9e4dbSFlorent Revest 		if (fmt[i + 1] == '%') {
839d9c9e4dbSFlorent Revest 			i++;
840d9c9e4dbSFlorent Revest 			continue;
841d9c9e4dbSFlorent Revest 		}
842d9c9e4dbSFlorent Revest 
843d9c9e4dbSFlorent Revest 		if (num_spec >= num_args) {
844d9c9e4dbSFlorent Revest 			err = -EINVAL;
84548cac3f4SFlorent Revest 			goto out;
846d9c9e4dbSFlorent Revest 		}
847d9c9e4dbSFlorent Revest 
848d9c9e4dbSFlorent Revest 		/* The string is zero-terminated so if fmt[i] != 0, we can
849d9c9e4dbSFlorent Revest 		 * always access fmt[i + 1], in the worst case it will be a 0
850d9c9e4dbSFlorent Revest 		 */
851d9c9e4dbSFlorent Revest 		i++;
852d9c9e4dbSFlorent Revest 
853d9c9e4dbSFlorent Revest 		/* skip optional "[0 +-][num]" width formatting field */
854d9c9e4dbSFlorent Revest 		while (fmt[i] == '0' || fmt[i] == '+'  || fmt[i] == '-' ||
855d9c9e4dbSFlorent Revest 		       fmt[i] == ' ')
856d9c9e4dbSFlorent Revest 			i++;
857d9c9e4dbSFlorent Revest 		if (fmt[i] >= '1' && fmt[i] <= '9') {
858d9c9e4dbSFlorent Revest 			i++;
859d9c9e4dbSFlorent Revest 			while (fmt[i] >= '0' && fmt[i] <= '9')
860d9c9e4dbSFlorent Revest 				i++;
861d9c9e4dbSFlorent Revest 		}
862d9c9e4dbSFlorent Revest 
863d9c9e4dbSFlorent Revest 		if (fmt[i] == 'p') {
86448cac3f4SFlorent Revest 			sizeof_cur_arg = sizeof(long);
865d9c9e4dbSFlorent Revest 
866d9c9e4dbSFlorent Revest 			if ((fmt[i + 1] == 'k' || fmt[i + 1] == 'u') &&
867d9c9e4dbSFlorent Revest 			    fmt[i + 2] == 's') {
868d9c9e4dbSFlorent Revest 				fmt_ptype = fmt[i + 1];
869d9c9e4dbSFlorent Revest 				i += 2;
870d9c9e4dbSFlorent Revest 				goto fmt_str;
871d9c9e4dbSFlorent Revest 			}
872d9c9e4dbSFlorent Revest 
873d9c9e4dbSFlorent Revest 			if (fmt[i + 1] == 0 || isspace(fmt[i + 1]) ||
874d9c9e4dbSFlorent Revest 			    ispunct(fmt[i + 1]) || fmt[i + 1] == 'K' ||
87548cac3f4SFlorent Revest 			    fmt[i + 1] == 'x' || fmt[i + 1] == 's' ||
87648cac3f4SFlorent Revest 			    fmt[i + 1] == 'S') {
877d9c9e4dbSFlorent Revest 				/* just kernel pointers */
87848cac3f4SFlorent Revest 				if (tmp_buf)
879d9c9e4dbSFlorent Revest 					cur_arg = raw_args[num_spec];
88048cac3f4SFlorent Revest 				i++;
88148cac3f4SFlorent Revest 				goto nocopy_fmt;
88248cac3f4SFlorent Revest 			}
88348cac3f4SFlorent Revest 
88448cac3f4SFlorent Revest 			if (fmt[i + 1] == 'B') {
88548cac3f4SFlorent Revest 				if (tmp_buf)  {
88648cac3f4SFlorent Revest 					err = snprintf(tmp_buf,
88748cac3f4SFlorent Revest 						       (tmp_buf_end - tmp_buf),
88848cac3f4SFlorent Revest 						       "%pB",
88948cac3f4SFlorent Revest 						       (void *)(long)raw_args[num_spec]);
89048cac3f4SFlorent Revest 					tmp_buf += (err + 1);
89148cac3f4SFlorent Revest 				}
89248cac3f4SFlorent Revest 
89348cac3f4SFlorent Revest 				i++;
89448cac3f4SFlorent Revest 				num_spec++;
89548cac3f4SFlorent Revest 				continue;
896d9c9e4dbSFlorent Revest 			}
897d9c9e4dbSFlorent Revest 
898d9c9e4dbSFlorent Revest 			/* only support "%pI4", "%pi4", "%pI6" and "%pi6". */
899d9c9e4dbSFlorent Revest 			if ((fmt[i + 1] != 'i' && fmt[i + 1] != 'I') ||
900d9c9e4dbSFlorent Revest 			    (fmt[i + 2] != '4' && fmt[i + 2] != '6')) {
901d9c9e4dbSFlorent Revest 				err = -EINVAL;
902d9c9e4dbSFlorent Revest 				goto out;
903d9c9e4dbSFlorent Revest 			}
904d9c9e4dbSFlorent Revest 
90548cac3f4SFlorent Revest 			i += 2;
90648cac3f4SFlorent Revest 			if (!tmp_buf)
90748cac3f4SFlorent Revest 				goto nocopy_fmt;
90848cac3f4SFlorent Revest 
90948cac3f4SFlorent Revest 			sizeof_cur_ip = (fmt[i] == '4') ? 4 : 16;
91048cac3f4SFlorent Revest 			if (tmp_buf_end - tmp_buf < sizeof_cur_ip) {
911d9c9e4dbSFlorent Revest 				err = -ENOSPC;
91248cac3f4SFlorent Revest 				goto out;
913d9c9e4dbSFlorent Revest 			}
914d9c9e4dbSFlorent Revest 
915d9c9e4dbSFlorent Revest 			unsafe_ptr = (char *)(long)raw_args[num_spec];
91648cac3f4SFlorent Revest 			err = copy_from_kernel_nofault(cur_ip, unsafe_ptr,
91748cac3f4SFlorent Revest 						       sizeof_cur_ip);
918d9c9e4dbSFlorent Revest 			if (err < 0)
91948cac3f4SFlorent Revest 				memset(cur_ip, 0, sizeof_cur_ip);
920d9c9e4dbSFlorent Revest 
92148cac3f4SFlorent Revest 			/* hack: bstr_printf expects IP addresses to be
92248cac3f4SFlorent Revest 			 * pre-formatted as strings, ironically, the easiest way
92348cac3f4SFlorent Revest 			 * to do that is to call snprintf.
92448cac3f4SFlorent Revest 			 */
92548cac3f4SFlorent Revest 			ip_spec[2] = fmt[i - 1];
92648cac3f4SFlorent Revest 			ip_spec[3] = fmt[i];
92748cac3f4SFlorent Revest 			err = snprintf(tmp_buf, tmp_buf_end - tmp_buf,
92848cac3f4SFlorent Revest 				       ip_spec, &cur_ip);
92948cac3f4SFlorent Revest 
93048cac3f4SFlorent Revest 			tmp_buf += err + 1;
93148cac3f4SFlorent Revest 			num_spec++;
93248cac3f4SFlorent Revest 
93348cac3f4SFlorent Revest 			continue;
934d9c9e4dbSFlorent Revest 		} else if (fmt[i] == 's') {
935d9c9e4dbSFlorent Revest 			fmt_ptype = fmt[i];
936d9c9e4dbSFlorent Revest fmt_str:
937d9c9e4dbSFlorent Revest 			if (fmt[i + 1] != 0 &&
938d9c9e4dbSFlorent Revest 			    !isspace(fmt[i + 1]) &&
939d9c9e4dbSFlorent Revest 			    !ispunct(fmt[i + 1])) {
940d9c9e4dbSFlorent Revest 				err = -EINVAL;
941d9c9e4dbSFlorent Revest 				goto out;
942d9c9e4dbSFlorent Revest 			}
943d9c9e4dbSFlorent Revest 
94448cac3f4SFlorent Revest 			if (!tmp_buf)
94548cac3f4SFlorent Revest 				goto nocopy_fmt;
94648cac3f4SFlorent Revest 
94748cac3f4SFlorent Revest 			if (tmp_buf_end == tmp_buf) {
948d9c9e4dbSFlorent Revest 				err = -ENOSPC;
94948cac3f4SFlorent Revest 				goto out;
950d9c9e4dbSFlorent Revest 			}
951d9c9e4dbSFlorent Revest 
952d9c9e4dbSFlorent Revest 			unsafe_ptr = (char *)(long)raw_args[num_spec];
953d9c9e4dbSFlorent Revest 			err = bpf_trace_copy_string(tmp_buf, unsafe_ptr,
95448cac3f4SFlorent Revest 						    fmt_ptype,
95548cac3f4SFlorent Revest 						    tmp_buf_end - tmp_buf);
956d9c9e4dbSFlorent Revest 			if (err < 0) {
957d9c9e4dbSFlorent Revest 				tmp_buf[0] = '\0';
958d9c9e4dbSFlorent Revest 				err = 1;
959d9c9e4dbSFlorent Revest 			}
960d9c9e4dbSFlorent Revest 
961d9c9e4dbSFlorent Revest 			tmp_buf += err;
96248cac3f4SFlorent Revest 			num_spec++;
963d9c9e4dbSFlorent Revest 
96448cac3f4SFlorent Revest 			continue;
9653478cfcfSKuniyuki Iwashima 		} else if (fmt[i] == 'c') {
9663478cfcfSKuniyuki Iwashima 			if (!tmp_buf)
9673478cfcfSKuniyuki Iwashima 				goto nocopy_fmt;
9683478cfcfSKuniyuki Iwashima 
9693478cfcfSKuniyuki Iwashima 			if (tmp_buf_end == tmp_buf) {
9703478cfcfSKuniyuki Iwashima 				err = -ENOSPC;
9713478cfcfSKuniyuki Iwashima 				goto out;
9723478cfcfSKuniyuki Iwashima 			}
9733478cfcfSKuniyuki Iwashima 
9743478cfcfSKuniyuki Iwashima 			*tmp_buf = raw_args[num_spec];
9753478cfcfSKuniyuki Iwashima 			tmp_buf++;
9763478cfcfSKuniyuki Iwashima 			num_spec++;
9773478cfcfSKuniyuki Iwashima 
9783478cfcfSKuniyuki Iwashima 			continue;
979d9c9e4dbSFlorent Revest 		}
980d9c9e4dbSFlorent Revest 
98148cac3f4SFlorent Revest 		sizeof_cur_arg = sizeof(int);
982d9c9e4dbSFlorent Revest 
983d9c9e4dbSFlorent Revest 		if (fmt[i] == 'l') {
98448cac3f4SFlorent Revest 			sizeof_cur_arg = sizeof(long);
985d9c9e4dbSFlorent Revest 			i++;
986d9c9e4dbSFlorent Revest 		}
987d9c9e4dbSFlorent Revest 		if (fmt[i] == 'l') {
98848cac3f4SFlorent Revest 			sizeof_cur_arg = sizeof(long long);
989d9c9e4dbSFlorent Revest 			i++;
990d9c9e4dbSFlorent Revest 		}
991d9c9e4dbSFlorent Revest 
992d9c9e4dbSFlorent Revest 		if (fmt[i] != 'i' && fmt[i] != 'd' && fmt[i] != 'u' &&
993d9c9e4dbSFlorent Revest 		    fmt[i] != 'x' && fmt[i] != 'X') {
994d9c9e4dbSFlorent Revest 			err = -EINVAL;
99548cac3f4SFlorent Revest 			goto out;
996d9c9e4dbSFlorent Revest 		}
997d9c9e4dbSFlorent Revest 
99848cac3f4SFlorent Revest 		if (tmp_buf)
999d9c9e4dbSFlorent Revest 			cur_arg = raw_args[num_spec];
100048cac3f4SFlorent Revest nocopy_fmt:
100148cac3f4SFlorent Revest 		if (tmp_buf) {
100248cac3f4SFlorent Revest 			tmp_buf = PTR_ALIGN(tmp_buf, sizeof(u32));
100348cac3f4SFlorent Revest 			if (tmp_buf_end - tmp_buf < sizeof_cur_arg) {
100448cac3f4SFlorent Revest 				err = -ENOSPC;
100548cac3f4SFlorent Revest 				goto out;
100648cac3f4SFlorent Revest 			}
100748cac3f4SFlorent Revest 
100848cac3f4SFlorent Revest 			if (sizeof_cur_arg == 8) {
100948cac3f4SFlorent Revest 				*(u32 *)tmp_buf = *(u32 *)&cur_arg;
101048cac3f4SFlorent Revest 				*(u32 *)(tmp_buf + 4) = *((u32 *)&cur_arg + 1);
101148cac3f4SFlorent Revest 			} else {
101248cac3f4SFlorent Revest 				*(u32 *)tmp_buf = (u32)(long)cur_arg;
101348cac3f4SFlorent Revest 			}
101448cac3f4SFlorent Revest 			tmp_buf += sizeof_cur_arg;
1015d9c9e4dbSFlorent Revest 		}
1016d9c9e4dbSFlorent Revest 		num_spec++;
1017d9c9e4dbSFlorent Revest 	}
1018d9c9e4dbSFlorent Revest 
1019d9c9e4dbSFlorent Revest 	err = 0;
1020d9c9e4dbSFlorent Revest out:
102148cac3f4SFlorent Revest 	if (err)
102248cac3f4SFlorent Revest 		bpf_bprintf_cleanup();
1023d9c9e4dbSFlorent Revest 	return err;
1024d9c9e4dbSFlorent Revest }
1025d9c9e4dbSFlorent Revest 
10267b15523aSFlorent Revest BPF_CALL_5(bpf_snprintf, char *, str, u32, str_size, char *, fmt,
10277b15523aSFlorent Revest 	   const void *, data, u32, data_len)
10287b15523aSFlorent Revest {
10297b15523aSFlorent Revest 	int err, num_args;
103048cac3f4SFlorent Revest 	u32 *bin_args;
10317b15523aSFlorent Revest 
1032335ff499SDave Marchevsky 	if (data_len % 8 || data_len > MAX_BPRINTF_VARARGS * 8 ||
10337b15523aSFlorent Revest 	    (data_len && !data))
10347b15523aSFlorent Revest 		return -EINVAL;
10357b15523aSFlorent Revest 	num_args = data_len / 8;
10367b15523aSFlorent Revest 
10377b15523aSFlorent Revest 	/* ARG_PTR_TO_CONST_STR guarantees that fmt is zero-terminated so we
10387b15523aSFlorent Revest 	 * can safely give an unbounded size.
10397b15523aSFlorent Revest 	 */
104048cac3f4SFlorent Revest 	err = bpf_bprintf_prepare(fmt, UINT_MAX, data, &bin_args, num_args);
10417b15523aSFlorent Revest 	if (err < 0)
10427b15523aSFlorent Revest 		return err;
10437b15523aSFlorent Revest 
104448cac3f4SFlorent Revest 	err = bstr_printf(str, str_size, fmt, bin_args);
10457b15523aSFlorent Revest 
104648cac3f4SFlorent Revest 	bpf_bprintf_cleanup();
10477b15523aSFlorent Revest 
10487b15523aSFlorent Revest 	return err + 1;
10497b15523aSFlorent Revest }
10507b15523aSFlorent Revest 
10517b15523aSFlorent Revest const struct bpf_func_proto bpf_snprintf_proto = {
10527b15523aSFlorent Revest 	.func		= bpf_snprintf,
10537b15523aSFlorent Revest 	.gpl_only	= true,
10547b15523aSFlorent Revest 	.ret_type	= RET_INTEGER,
10557b15523aSFlorent Revest 	.arg1_type	= ARG_PTR_TO_MEM_OR_NULL,
10567b15523aSFlorent Revest 	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
10577b15523aSFlorent Revest 	.arg3_type	= ARG_PTR_TO_CONST_STR,
1058216e3cd2SHao Luo 	.arg4_type	= ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,
10597b15523aSFlorent Revest 	.arg5_type	= ARG_CONST_SIZE_OR_ZERO,
10607b15523aSFlorent Revest };
10617b15523aSFlorent Revest 
1062b00628b1SAlexei Starovoitov /* BPF map elements can contain 'struct bpf_timer'.
1063b00628b1SAlexei Starovoitov  * Such map owns all of its BPF timers.
1064b00628b1SAlexei Starovoitov  * 'struct bpf_timer' is allocated as part of map element allocation
1065b00628b1SAlexei Starovoitov  * and it's zero initialized.
1066b00628b1SAlexei Starovoitov  * That space is used to keep 'struct bpf_timer_kern'.
1067b00628b1SAlexei Starovoitov  * bpf_timer_init() allocates 'struct bpf_hrtimer', inits hrtimer, and
1068b00628b1SAlexei Starovoitov  * remembers 'struct bpf_map *' pointer it's part of.
1069b00628b1SAlexei Starovoitov  * bpf_timer_set_callback() increments prog refcnt and assign bpf callback_fn.
1070b00628b1SAlexei Starovoitov  * bpf_timer_start() arms the timer.
1071b00628b1SAlexei Starovoitov  * If user space reference to a map goes to zero at this point
1072b00628b1SAlexei Starovoitov  * ops->map_release_uref callback is responsible for cancelling the timers,
1073b00628b1SAlexei Starovoitov  * freeing their memory, and decrementing prog's refcnts.
1074b00628b1SAlexei Starovoitov  * bpf_timer_cancel() cancels the timer and decrements prog's refcnt.
1075b00628b1SAlexei Starovoitov  * Inner maps can contain bpf timers as well. ops->map_release_uref is
1076b00628b1SAlexei Starovoitov  * freeing the timers when inner map is replaced or deleted by user space.
1077b00628b1SAlexei Starovoitov  */
1078b00628b1SAlexei Starovoitov struct bpf_hrtimer {
1079b00628b1SAlexei Starovoitov 	struct hrtimer timer;
1080b00628b1SAlexei Starovoitov 	struct bpf_map *map;
1081b00628b1SAlexei Starovoitov 	struct bpf_prog *prog;
1082b00628b1SAlexei Starovoitov 	void __rcu *callback_fn;
1083b00628b1SAlexei Starovoitov 	void *value;
1084b00628b1SAlexei Starovoitov };
1085b00628b1SAlexei Starovoitov 
1086b00628b1SAlexei Starovoitov /* the actual struct hidden inside uapi struct bpf_timer */
1087b00628b1SAlexei Starovoitov struct bpf_timer_kern {
1088b00628b1SAlexei Starovoitov 	struct bpf_hrtimer *timer;
1089b00628b1SAlexei Starovoitov 	/* bpf_spin_lock is used here instead of spinlock_t to make
1090c561d110STom Rix 	 * sure that it always fits into space reserved by struct bpf_timer
1091b00628b1SAlexei Starovoitov 	 * regardless of LOCKDEP and spinlock debug flags.
1092b00628b1SAlexei Starovoitov 	 */
1093b00628b1SAlexei Starovoitov 	struct bpf_spin_lock lock;
1094b00628b1SAlexei Starovoitov } __attribute__((aligned(8)));
1095b00628b1SAlexei Starovoitov 
1096b00628b1SAlexei Starovoitov static DEFINE_PER_CPU(struct bpf_hrtimer *, hrtimer_running);
1097b00628b1SAlexei Starovoitov 
1098b00628b1SAlexei Starovoitov static enum hrtimer_restart bpf_timer_cb(struct hrtimer *hrtimer)
1099b00628b1SAlexei Starovoitov {
1100b00628b1SAlexei Starovoitov 	struct bpf_hrtimer *t = container_of(hrtimer, struct bpf_hrtimer, timer);
1101b00628b1SAlexei Starovoitov 	struct bpf_map *map = t->map;
1102b00628b1SAlexei Starovoitov 	void *value = t->value;
1103102acbacSKees Cook 	bpf_callback_t callback_fn;
1104b00628b1SAlexei Starovoitov 	void *key;
1105b00628b1SAlexei Starovoitov 	u32 idx;
1106b00628b1SAlexei Starovoitov 
11073bd916eeSYonghong Song 	BTF_TYPE_EMIT(struct bpf_timer);
1108b00628b1SAlexei Starovoitov 	callback_fn = rcu_dereference_check(t->callback_fn, rcu_read_lock_bh_held());
1109b00628b1SAlexei Starovoitov 	if (!callback_fn)
1110b00628b1SAlexei Starovoitov 		goto out;
1111b00628b1SAlexei Starovoitov 
1112b00628b1SAlexei Starovoitov 	/* bpf_timer_cb() runs in hrtimer_run_softirq. It doesn't migrate and
1113b00628b1SAlexei Starovoitov 	 * cannot be preempted by another bpf_timer_cb() on the same cpu.
1114b00628b1SAlexei Starovoitov 	 * Remember the timer this callback is servicing to prevent
1115b00628b1SAlexei Starovoitov 	 * deadlock if callback_fn() calls bpf_timer_cancel() or
1116b00628b1SAlexei Starovoitov 	 * bpf_map_delete_elem() on the same timer.
1117b00628b1SAlexei Starovoitov 	 */
1118b00628b1SAlexei Starovoitov 	this_cpu_write(hrtimer_running, t);
1119b00628b1SAlexei Starovoitov 	if (map->map_type == BPF_MAP_TYPE_ARRAY) {
1120b00628b1SAlexei Starovoitov 		struct bpf_array *array = container_of(map, struct bpf_array, map);
1121b00628b1SAlexei Starovoitov 
1122b00628b1SAlexei Starovoitov 		/* compute the key */
1123b00628b1SAlexei Starovoitov 		idx = ((char *)value - array->value) / array->elem_size;
1124b00628b1SAlexei Starovoitov 		key = &idx;
1125b00628b1SAlexei Starovoitov 	} else { /* hash or lru */
1126b00628b1SAlexei Starovoitov 		key = value - round_up(map->key_size, 8);
1127b00628b1SAlexei Starovoitov 	}
1128b00628b1SAlexei Starovoitov 
1129102acbacSKees Cook 	callback_fn((u64)(long)map, (u64)(long)key, (u64)(long)value, 0, 0);
1130bfc6bb74SAlexei Starovoitov 	/* The verifier checked that return value is zero. */
1131b00628b1SAlexei Starovoitov 
1132b00628b1SAlexei Starovoitov 	this_cpu_write(hrtimer_running, NULL);
1133b00628b1SAlexei Starovoitov out:
1134b00628b1SAlexei Starovoitov 	return HRTIMER_NORESTART;
1135b00628b1SAlexei Starovoitov }
1136b00628b1SAlexei Starovoitov 
1137b00628b1SAlexei Starovoitov BPF_CALL_3(bpf_timer_init, struct bpf_timer_kern *, timer, struct bpf_map *, map,
1138b00628b1SAlexei Starovoitov 	   u64, flags)
1139b00628b1SAlexei Starovoitov {
1140b00628b1SAlexei Starovoitov 	clockid_t clockid = flags & (MAX_CLOCKS - 1);
1141b00628b1SAlexei Starovoitov 	struct bpf_hrtimer *t;
1142b00628b1SAlexei Starovoitov 	int ret = 0;
1143b00628b1SAlexei Starovoitov 
1144b00628b1SAlexei Starovoitov 	BUILD_BUG_ON(MAX_CLOCKS != 16);
1145b00628b1SAlexei Starovoitov 	BUILD_BUG_ON(sizeof(struct bpf_timer_kern) > sizeof(struct bpf_timer));
1146b00628b1SAlexei Starovoitov 	BUILD_BUG_ON(__alignof__(struct bpf_timer_kern) != __alignof__(struct bpf_timer));
1147b00628b1SAlexei Starovoitov 
1148b00628b1SAlexei Starovoitov 	if (in_nmi())
1149b00628b1SAlexei Starovoitov 		return -EOPNOTSUPP;
1150b00628b1SAlexei Starovoitov 
1151b00628b1SAlexei Starovoitov 	if (flags >= MAX_CLOCKS ||
1152b00628b1SAlexei Starovoitov 	    /* similar to timerfd except _ALARM variants are not supported */
1153b00628b1SAlexei Starovoitov 	    (clockid != CLOCK_MONOTONIC &&
1154b00628b1SAlexei Starovoitov 	     clockid != CLOCK_REALTIME &&
1155b00628b1SAlexei Starovoitov 	     clockid != CLOCK_BOOTTIME))
1156b00628b1SAlexei Starovoitov 		return -EINVAL;
1157b00628b1SAlexei Starovoitov 	__bpf_spin_lock_irqsave(&timer->lock);
1158b00628b1SAlexei Starovoitov 	t = timer->timer;
1159b00628b1SAlexei Starovoitov 	if (t) {
1160b00628b1SAlexei Starovoitov 		ret = -EBUSY;
1161b00628b1SAlexei Starovoitov 		goto out;
1162b00628b1SAlexei Starovoitov 	}
1163b00628b1SAlexei Starovoitov 	if (!atomic64_read(&map->usercnt)) {
1164b00628b1SAlexei Starovoitov 		/* maps with timers must be either held by user space
1165b00628b1SAlexei Starovoitov 		 * or pinned in bpffs.
1166b00628b1SAlexei Starovoitov 		 */
1167b00628b1SAlexei Starovoitov 		ret = -EPERM;
1168b00628b1SAlexei Starovoitov 		goto out;
1169b00628b1SAlexei Starovoitov 	}
1170b00628b1SAlexei Starovoitov 	/* allocate hrtimer via map_kmalloc to use memcg accounting */
1171b00628b1SAlexei Starovoitov 	t = bpf_map_kmalloc_node(map, sizeof(*t), GFP_ATOMIC, map->numa_node);
1172b00628b1SAlexei Starovoitov 	if (!t) {
1173b00628b1SAlexei Starovoitov 		ret = -ENOMEM;
1174b00628b1SAlexei Starovoitov 		goto out;
1175b00628b1SAlexei Starovoitov 	}
1176db559117SKumar Kartikeya Dwivedi 	t->value = (void *)timer - map->record->timer_off;
1177b00628b1SAlexei Starovoitov 	t->map = map;
1178b00628b1SAlexei Starovoitov 	t->prog = NULL;
1179b00628b1SAlexei Starovoitov 	rcu_assign_pointer(t->callback_fn, NULL);
1180b00628b1SAlexei Starovoitov 	hrtimer_init(&t->timer, clockid, HRTIMER_MODE_REL_SOFT);
1181b00628b1SAlexei Starovoitov 	t->timer.function = bpf_timer_cb;
1182b00628b1SAlexei Starovoitov 	timer->timer = t;
1183b00628b1SAlexei Starovoitov out:
1184b00628b1SAlexei Starovoitov 	__bpf_spin_unlock_irqrestore(&timer->lock);
1185b00628b1SAlexei Starovoitov 	return ret;
1186b00628b1SAlexei Starovoitov }
1187b00628b1SAlexei Starovoitov 
1188b00628b1SAlexei Starovoitov static const struct bpf_func_proto bpf_timer_init_proto = {
1189b00628b1SAlexei Starovoitov 	.func		= bpf_timer_init,
1190b00628b1SAlexei Starovoitov 	.gpl_only	= true,
1191b00628b1SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
1192b00628b1SAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_TIMER,
1193b00628b1SAlexei Starovoitov 	.arg2_type	= ARG_CONST_MAP_PTR,
1194b00628b1SAlexei Starovoitov 	.arg3_type	= ARG_ANYTHING,
1195b00628b1SAlexei Starovoitov };
1196b00628b1SAlexei Starovoitov 
1197b00628b1SAlexei Starovoitov BPF_CALL_3(bpf_timer_set_callback, struct bpf_timer_kern *, timer, void *, callback_fn,
1198b00628b1SAlexei Starovoitov 	   struct bpf_prog_aux *, aux)
1199b00628b1SAlexei Starovoitov {
1200b00628b1SAlexei Starovoitov 	struct bpf_prog *prev, *prog = aux->prog;
1201b00628b1SAlexei Starovoitov 	struct bpf_hrtimer *t;
1202b00628b1SAlexei Starovoitov 	int ret = 0;
1203b00628b1SAlexei Starovoitov 
1204b00628b1SAlexei Starovoitov 	if (in_nmi())
1205b00628b1SAlexei Starovoitov 		return -EOPNOTSUPP;
1206b00628b1SAlexei Starovoitov 	__bpf_spin_lock_irqsave(&timer->lock);
1207b00628b1SAlexei Starovoitov 	t = timer->timer;
1208b00628b1SAlexei Starovoitov 	if (!t) {
1209b00628b1SAlexei Starovoitov 		ret = -EINVAL;
1210b00628b1SAlexei Starovoitov 		goto out;
1211b00628b1SAlexei Starovoitov 	}
1212b00628b1SAlexei Starovoitov 	if (!atomic64_read(&t->map->usercnt)) {
1213b00628b1SAlexei Starovoitov 		/* maps with timers must be either held by user space
1214b00628b1SAlexei Starovoitov 		 * or pinned in bpffs. Otherwise timer might still be
1215b00628b1SAlexei Starovoitov 		 * running even when bpf prog is detached and user space
1216b00628b1SAlexei Starovoitov 		 * is gone, since map_release_uref won't ever be called.
1217b00628b1SAlexei Starovoitov 		 */
1218b00628b1SAlexei Starovoitov 		ret = -EPERM;
1219b00628b1SAlexei Starovoitov 		goto out;
1220b00628b1SAlexei Starovoitov 	}
1221b00628b1SAlexei Starovoitov 	prev = t->prog;
1222b00628b1SAlexei Starovoitov 	if (prev != prog) {
1223b00628b1SAlexei Starovoitov 		/* Bump prog refcnt once. Every bpf_timer_set_callback()
1224b00628b1SAlexei Starovoitov 		 * can pick different callback_fn-s within the same prog.
1225b00628b1SAlexei Starovoitov 		 */
1226b00628b1SAlexei Starovoitov 		prog = bpf_prog_inc_not_zero(prog);
1227b00628b1SAlexei Starovoitov 		if (IS_ERR(prog)) {
1228b00628b1SAlexei Starovoitov 			ret = PTR_ERR(prog);
1229b00628b1SAlexei Starovoitov 			goto out;
1230b00628b1SAlexei Starovoitov 		}
1231b00628b1SAlexei Starovoitov 		if (prev)
1232b00628b1SAlexei Starovoitov 			/* Drop prev prog refcnt when swapping with new prog */
1233b00628b1SAlexei Starovoitov 			bpf_prog_put(prev);
1234b00628b1SAlexei Starovoitov 		t->prog = prog;
1235b00628b1SAlexei Starovoitov 	}
1236b00628b1SAlexei Starovoitov 	rcu_assign_pointer(t->callback_fn, callback_fn);
1237b00628b1SAlexei Starovoitov out:
1238b00628b1SAlexei Starovoitov 	__bpf_spin_unlock_irqrestore(&timer->lock);
1239b00628b1SAlexei Starovoitov 	return ret;
1240b00628b1SAlexei Starovoitov }
1241b00628b1SAlexei Starovoitov 
1242b00628b1SAlexei Starovoitov static const struct bpf_func_proto bpf_timer_set_callback_proto = {
1243b00628b1SAlexei Starovoitov 	.func		= bpf_timer_set_callback,
1244b00628b1SAlexei Starovoitov 	.gpl_only	= true,
1245b00628b1SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
1246b00628b1SAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_TIMER,
1247b00628b1SAlexei Starovoitov 	.arg2_type	= ARG_PTR_TO_FUNC,
1248b00628b1SAlexei Starovoitov };
1249b00628b1SAlexei Starovoitov 
1250b00628b1SAlexei Starovoitov BPF_CALL_3(bpf_timer_start, struct bpf_timer_kern *, timer, u64, nsecs, u64, flags)
1251b00628b1SAlexei Starovoitov {
1252b00628b1SAlexei Starovoitov 	struct bpf_hrtimer *t;
1253b00628b1SAlexei Starovoitov 	int ret = 0;
1254b00628b1SAlexei Starovoitov 
1255b00628b1SAlexei Starovoitov 	if (in_nmi())
1256b00628b1SAlexei Starovoitov 		return -EOPNOTSUPP;
1257b00628b1SAlexei Starovoitov 	if (flags)
1258b00628b1SAlexei Starovoitov 		return -EINVAL;
1259b00628b1SAlexei Starovoitov 	__bpf_spin_lock_irqsave(&timer->lock);
1260b00628b1SAlexei Starovoitov 	t = timer->timer;
1261b00628b1SAlexei Starovoitov 	if (!t || !t->prog) {
1262b00628b1SAlexei Starovoitov 		ret = -EINVAL;
1263b00628b1SAlexei Starovoitov 		goto out;
1264b00628b1SAlexei Starovoitov 	}
1265b00628b1SAlexei Starovoitov 	hrtimer_start(&t->timer, ns_to_ktime(nsecs), HRTIMER_MODE_REL_SOFT);
1266b00628b1SAlexei Starovoitov out:
1267b00628b1SAlexei Starovoitov 	__bpf_spin_unlock_irqrestore(&timer->lock);
1268b00628b1SAlexei Starovoitov 	return ret;
1269b00628b1SAlexei Starovoitov }
1270b00628b1SAlexei Starovoitov 
1271b00628b1SAlexei Starovoitov static const struct bpf_func_proto bpf_timer_start_proto = {
1272b00628b1SAlexei Starovoitov 	.func		= bpf_timer_start,
1273b00628b1SAlexei Starovoitov 	.gpl_only	= true,
1274b00628b1SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
1275b00628b1SAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_TIMER,
1276b00628b1SAlexei Starovoitov 	.arg2_type	= ARG_ANYTHING,
1277b00628b1SAlexei Starovoitov 	.arg3_type	= ARG_ANYTHING,
1278b00628b1SAlexei Starovoitov };
1279b00628b1SAlexei Starovoitov 
1280b00628b1SAlexei Starovoitov static void drop_prog_refcnt(struct bpf_hrtimer *t)
1281b00628b1SAlexei Starovoitov {
1282b00628b1SAlexei Starovoitov 	struct bpf_prog *prog = t->prog;
1283b00628b1SAlexei Starovoitov 
1284b00628b1SAlexei Starovoitov 	if (prog) {
1285b00628b1SAlexei Starovoitov 		bpf_prog_put(prog);
1286b00628b1SAlexei Starovoitov 		t->prog = NULL;
1287b00628b1SAlexei Starovoitov 		rcu_assign_pointer(t->callback_fn, NULL);
1288b00628b1SAlexei Starovoitov 	}
1289b00628b1SAlexei Starovoitov }
1290b00628b1SAlexei Starovoitov 
1291b00628b1SAlexei Starovoitov BPF_CALL_1(bpf_timer_cancel, struct bpf_timer_kern *, timer)
1292b00628b1SAlexei Starovoitov {
1293b00628b1SAlexei Starovoitov 	struct bpf_hrtimer *t;
1294b00628b1SAlexei Starovoitov 	int ret = 0;
1295b00628b1SAlexei Starovoitov 
1296b00628b1SAlexei Starovoitov 	if (in_nmi())
1297b00628b1SAlexei Starovoitov 		return -EOPNOTSUPP;
1298b00628b1SAlexei Starovoitov 	__bpf_spin_lock_irqsave(&timer->lock);
1299b00628b1SAlexei Starovoitov 	t = timer->timer;
1300b00628b1SAlexei Starovoitov 	if (!t) {
1301b00628b1SAlexei Starovoitov 		ret = -EINVAL;
1302b00628b1SAlexei Starovoitov 		goto out;
1303b00628b1SAlexei Starovoitov 	}
1304b00628b1SAlexei Starovoitov 	if (this_cpu_read(hrtimer_running) == t) {
1305b00628b1SAlexei Starovoitov 		/* If bpf callback_fn is trying to bpf_timer_cancel()
1306b00628b1SAlexei Starovoitov 		 * its own timer the hrtimer_cancel() will deadlock
1307b00628b1SAlexei Starovoitov 		 * since it waits for callback_fn to finish
1308b00628b1SAlexei Starovoitov 		 */
1309b00628b1SAlexei Starovoitov 		ret = -EDEADLK;
1310b00628b1SAlexei Starovoitov 		goto out;
1311b00628b1SAlexei Starovoitov 	}
1312b00628b1SAlexei Starovoitov 	drop_prog_refcnt(t);
1313b00628b1SAlexei Starovoitov out:
1314b00628b1SAlexei Starovoitov 	__bpf_spin_unlock_irqrestore(&timer->lock);
1315b00628b1SAlexei Starovoitov 	/* Cancel the timer and wait for associated callback to finish
1316b00628b1SAlexei Starovoitov 	 * if it was running.
1317b00628b1SAlexei Starovoitov 	 */
1318b00628b1SAlexei Starovoitov 	ret = ret ?: hrtimer_cancel(&t->timer);
1319b00628b1SAlexei Starovoitov 	return ret;
1320b00628b1SAlexei Starovoitov }
1321b00628b1SAlexei Starovoitov 
1322b00628b1SAlexei Starovoitov static const struct bpf_func_proto bpf_timer_cancel_proto = {
1323b00628b1SAlexei Starovoitov 	.func		= bpf_timer_cancel,
1324b00628b1SAlexei Starovoitov 	.gpl_only	= true,
1325b00628b1SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
1326b00628b1SAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_TIMER,
1327b00628b1SAlexei Starovoitov };
1328b00628b1SAlexei Starovoitov 
1329b00628b1SAlexei Starovoitov /* This function is called by map_delete/update_elem for individual element and
1330b00628b1SAlexei Starovoitov  * by ops->map_release_uref when the user space reference to a map reaches zero.
1331b00628b1SAlexei Starovoitov  */
1332b00628b1SAlexei Starovoitov void bpf_timer_cancel_and_free(void *val)
1333b00628b1SAlexei Starovoitov {
1334b00628b1SAlexei Starovoitov 	struct bpf_timer_kern *timer = val;
1335b00628b1SAlexei Starovoitov 	struct bpf_hrtimer *t;
1336b00628b1SAlexei Starovoitov 
1337b00628b1SAlexei Starovoitov 	/* Performance optimization: read timer->timer without lock first. */
1338b00628b1SAlexei Starovoitov 	if (!READ_ONCE(timer->timer))
1339b00628b1SAlexei Starovoitov 		return;
1340b00628b1SAlexei Starovoitov 
1341b00628b1SAlexei Starovoitov 	__bpf_spin_lock_irqsave(&timer->lock);
1342b00628b1SAlexei Starovoitov 	/* re-read it under lock */
1343b00628b1SAlexei Starovoitov 	t = timer->timer;
1344b00628b1SAlexei Starovoitov 	if (!t)
1345b00628b1SAlexei Starovoitov 		goto out;
1346b00628b1SAlexei Starovoitov 	drop_prog_refcnt(t);
1347b00628b1SAlexei Starovoitov 	/* The subsequent bpf_timer_start/cancel() helpers won't be able to use
1348b00628b1SAlexei Starovoitov 	 * this timer, since it won't be initialized.
1349b00628b1SAlexei Starovoitov 	 */
1350b00628b1SAlexei Starovoitov 	timer->timer = NULL;
1351b00628b1SAlexei Starovoitov out:
1352b00628b1SAlexei Starovoitov 	__bpf_spin_unlock_irqrestore(&timer->lock);
1353b00628b1SAlexei Starovoitov 	if (!t)
1354b00628b1SAlexei Starovoitov 		return;
1355b00628b1SAlexei Starovoitov 	/* Cancel the timer and wait for callback to complete if it was running.
1356b00628b1SAlexei Starovoitov 	 * If hrtimer_cancel() can be safely called it's safe to call kfree(t)
1357b00628b1SAlexei Starovoitov 	 * right after for both preallocated and non-preallocated maps.
1358b00628b1SAlexei Starovoitov 	 * The timer->timer = NULL was already done and no code path can
1359b00628b1SAlexei Starovoitov 	 * see address 't' anymore.
1360b00628b1SAlexei Starovoitov 	 *
1361b00628b1SAlexei Starovoitov 	 * Check that bpf_map_delete/update_elem() wasn't called from timer
1362b00628b1SAlexei Starovoitov 	 * callback_fn. In such case don't call hrtimer_cancel() (since it will
1363b00628b1SAlexei Starovoitov 	 * deadlock) and don't call hrtimer_try_to_cancel() (since it will just
1364b00628b1SAlexei Starovoitov 	 * return -1). Though callback_fn is still running on this cpu it's
1365b00628b1SAlexei Starovoitov 	 * safe to do kfree(t) because bpf_timer_cb() read everything it needed
1366b00628b1SAlexei Starovoitov 	 * from 't'. The bpf subprog callback_fn won't be able to access 't',
1367b00628b1SAlexei Starovoitov 	 * since timer->timer = NULL was already done. The timer will be
1368b00628b1SAlexei Starovoitov 	 * effectively cancelled because bpf_timer_cb() will return
1369b00628b1SAlexei Starovoitov 	 * HRTIMER_NORESTART.
1370b00628b1SAlexei Starovoitov 	 */
1371b00628b1SAlexei Starovoitov 	if (this_cpu_read(hrtimer_running) != t)
1372b00628b1SAlexei Starovoitov 		hrtimer_cancel(&t->timer);
1373b00628b1SAlexei Starovoitov 	kfree(t);
1374b00628b1SAlexei Starovoitov }
1375b00628b1SAlexei Starovoitov 
1376c0a5a21cSKumar Kartikeya Dwivedi BPF_CALL_2(bpf_kptr_xchg, void *, map_value, void *, ptr)
1377c0a5a21cSKumar Kartikeya Dwivedi {
1378c0a5a21cSKumar Kartikeya Dwivedi 	unsigned long *kptr = map_value;
1379c0a5a21cSKumar Kartikeya Dwivedi 
1380c0a5a21cSKumar Kartikeya Dwivedi 	return xchg(kptr, (unsigned long)ptr);
1381c0a5a21cSKumar Kartikeya Dwivedi }
1382c0a5a21cSKumar Kartikeya Dwivedi 
1383c0a5a21cSKumar Kartikeya Dwivedi /* Unlike other PTR_TO_BTF_ID helpers the btf_id in bpf_kptr_xchg()
138447e34cb7SDave Marchevsky  * helper is determined dynamically by the verifier. Use BPF_PTR_POISON to
138547e34cb7SDave Marchevsky  * denote type that verifier will determine.
1386c0a5a21cSKumar Kartikeya Dwivedi  */
1387dc368e1cSJoanne Koong static const struct bpf_func_proto bpf_kptr_xchg_proto = {
1388c0a5a21cSKumar Kartikeya Dwivedi 	.func         = bpf_kptr_xchg,
1389c0a5a21cSKumar Kartikeya Dwivedi 	.gpl_only     = false,
1390c0a5a21cSKumar Kartikeya Dwivedi 	.ret_type     = RET_PTR_TO_BTF_ID_OR_NULL,
1391c0a5a21cSKumar Kartikeya Dwivedi 	.ret_btf_id   = BPF_PTR_POISON,
1392c0a5a21cSKumar Kartikeya Dwivedi 	.arg1_type    = ARG_PTR_TO_KPTR,
1393c0a5a21cSKumar Kartikeya Dwivedi 	.arg2_type    = ARG_PTR_TO_BTF_ID_OR_NULL | OBJ_RELEASE,
1394c0a5a21cSKumar Kartikeya Dwivedi 	.arg2_btf_id  = BPF_PTR_POISON,
1395c0a5a21cSKumar Kartikeya Dwivedi };
1396c0a5a21cSKumar Kartikeya Dwivedi 
1397263ae152SJoanne Koong /* Since the upper 8 bits of dynptr->size is reserved, the
1398263ae152SJoanne Koong  * maximum supported size is 2^24 - 1.
1399263ae152SJoanne Koong  */
1400263ae152SJoanne Koong #define DYNPTR_MAX_SIZE	((1UL << 24) - 1)
1401263ae152SJoanne Koong #define DYNPTR_TYPE_SHIFT	28
140213bbbfbeSJoanne Koong #define DYNPTR_SIZE_MASK	0xFFFFFF
140313bbbfbeSJoanne Koong #define DYNPTR_RDONLY_BIT	BIT(31)
140413bbbfbeSJoanne Koong 
140513bbbfbeSJoanne Koong static bool bpf_dynptr_is_rdonly(struct bpf_dynptr_kern *ptr)
140613bbbfbeSJoanne Koong {
140713bbbfbeSJoanne Koong 	return ptr->size & DYNPTR_RDONLY_BIT;
140813bbbfbeSJoanne Koong }
1409263ae152SJoanne Koong 
1410263ae152SJoanne Koong static void bpf_dynptr_set_type(struct bpf_dynptr_kern *ptr, enum bpf_dynptr_type type)
1411263ae152SJoanne Koong {
1412263ae152SJoanne Koong 	ptr->size |= type << DYNPTR_TYPE_SHIFT;
1413263ae152SJoanne Koong }
1414263ae152SJoanne Koong 
141551df4865SRoberto Sassu u32 bpf_dynptr_get_size(struct bpf_dynptr_kern *ptr)
141613bbbfbeSJoanne Koong {
141713bbbfbeSJoanne Koong 	return ptr->size & DYNPTR_SIZE_MASK;
141813bbbfbeSJoanne Koong }
141913bbbfbeSJoanne Koong 
1420bc34dee6SJoanne Koong int bpf_dynptr_check_size(u32 size)
1421263ae152SJoanne Koong {
1422263ae152SJoanne Koong 	return size > DYNPTR_MAX_SIZE ? -E2BIG : 0;
1423263ae152SJoanne Koong }
1424263ae152SJoanne Koong 
1425bc34dee6SJoanne Koong void bpf_dynptr_init(struct bpf_dynptr_kern *ptr, void *data,
1426263ae152SJoanne Koong 		     enum bpf_dynptr_type type, u32 offset, u32 size)
1427263ae152SJoanne Koong {
1428263ae152SJoanne Koong 	ptr->data = data;
1429263ae152SJoanne Koong 	ptr->offset = offset;
1430263ae152SJoanne Koong 	ptr->size = size;
1431263ae152SJoanne Koong 	bpf_dynptr_set_type(ptr, type);
1432263ae152SJoanne Koong }
1433263ae152SJoanne Koong 
1434bc34dee6SJoanne Koong void bpf_dynptr_set_null(struct bpf_dynptr_kern *ptr)
1435263ae152SJoanne Koong {
1436263ae152SJoanne Koong 	memset(ptr, 0, sizeof(*ptr));
1437263ae152SJoanne Koong }
1438263ae152SJoanne Koong 
143913bbbfbeSJoanne Koong static int bpf_dynptr_check_off_len(struct bpf_dynptr_kern *ptr, u32 offset, u32 len)
144013bbbfbeSJoanne Koong {
144113bbbfbeSJoanne Koong 	u32 size = bpf_dynptr_get_size(ptr);
144213bbbfbeSJoanne Koong 
144313bbbfbeSJoanne Koong 	if (len > size || offset > size - len)
144413bbbfbeSJoanne Koong 		return -E2BIG;
144513bbbfbeSJoanne Koong 
144613bbbfbeSJoanne Koong 	return 0;
144713bbbfbeSJoanne Koong }
144813bbbfbeSJoanne Koong 
1449263ae152SJoanne Koong BPF_CALL_4(bpf_dynptr_from_mem, void *, data, u32, size, u64, flags, struct bpf_dynptr_kern *, ptr)
1450263ae152SJoanne Koong {
1451263ae152SJoanne Koong 	int err;
1452263ae152SJoanne Koong 
145300f14641SRoberto Sassu 	BTF_TYPE_EMIT(struct bpf_dynptr);
145400f14641SRoberto Sassu 
1455263ae152SJoanne Koong 	err = bpf_dynptr_check_size(size);
1456263ae152SJoanne Koong 	if (err)
1457263ae152SJoanne Koong 		goto error;
1458263ae152SJoanne Koong 
1459263ae152SJoanne Koong 	/* flags is currently unsupported */
1460263ae152SJoanne Koong 	if (flags) {
1461263ae152SJoanne Koong 		err = -EINVAL;
1462263ae152SJoanne Koong 		goto error;
1463263ae152SJoanne Koong 	}
1464263ae152SJoanne Koong 
1465263ae152SJoanne Koong 	bpf_dynptr_init(ptr, data, BPF_DYNPTR_TYPE_LOCAL, 0, size);
1466263ae152SJoanne Koong 
1467263ae152SJoanne Koong 	return 0;
1468263ae152SJoanne Koong 
1469263ae152SJoanne Koong error:
1470263ae152SJoanne Koong 	bpf_dynptr_set_null(ptr);
1471263ae152SJoanne Koong 	return err;
1472263ae152SJoanne Koong }
1473263ae152SJoanne Koong 
1474dc368e1cSJoanne Koong static const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
1475263ae152SJoanne Koong 	.func		= bpf_dynptr_from_mem,
1476263ae152SJoanne Koong 	.gpl_only	= false,
1477263ae152SJoanne Koong 	.ret_type	= RET_INTEGER,
1478263ae152SJoanne Koong 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
1479263ae152SJoanne Koong 	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
1480263ae152SJoanne Koong 	.arg3_type	= ARG_ANYTHING,
1481263ae152SJoanne Koong 	.arg4_type	= ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT,
1482263ae152SJoanne Koong };
1483263ae152SJoanne Koong 
1484f8d3da4eSJoanne Koong BPF_CALL_5(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src,
1485f8d3da4eSJoanne Koong 	   u32, offset, u64, flags)
148613bbbfbeSJoanne Koong {
148713bbbfbeSJoanne Koong 	int err;
148813bbbfbeSJoanne Koong 
1489f8d3da4eSJoanne Koong 	if (!src->data || flags)
149013bbbfbeSJoanne Koong 		return -EINVAL;
149113bbbfbeSJoanne Koong 
149213bbbfbeSJoanne Koong 	err = bpf_dynptr_check_off_len(src, offset, len);
149313bbbfbeSJoanne Koong 	if (err)
149413bbbfbeSJoanne Koong 		return err;
149513bbbfbeSJoanne Koong 
149613bbbfbeSJoanne Koong 	memcpy(dst, src->data + src->offset + offset, len);
149713bbbfbeSJoanne Koong 
149813bbbfbeSJoanne Koong 	return 0;
149913bbbfbeSJoanne Koong }
150013bbbfbeSJoanne Koong 
1501dc368e1cSJoanne Koong static const struct bpf_func_proto bpf_dynptr_read_proto = {
150213bbbfbeSJoanne Koong 	.func		= bpf_dynptr_read,
150313bbbfbeSJoanne Koong 	.gpl_only	= false,
150413bbbfbeSJoanne Koong 	.ret_type	= RET_INTEGER,
150513bbbfbeSJoanne Koong 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
150613bbbfbeSJoanne Koong 	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
150713bbbfbeSJoanne Koong 	.arg3_type	= ARG_PTR_TO_DYNPTR,
150813bbbfbeSJoanne Koong 	.arg4_type	= ARG_ANYTHING,
1509f8d3da4eSJoanne Koong 	.arg5_type	= ARG_ANYTHING,
151013bbbfbeSJoanne Koong };
151113bbbfbeSJoanne Koong 
1512f8d3da4eSJoanne Koong BPF_CALL_5(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, src,
1513f8d3da4eSJoanne Koong 	   u32, len, u64, flags)
151413bbbfbeSJoanne Koong {
151513bbbfbeSJoanne Koong 	int err;
151613bbbfbeSJoanne Koong 
1517f8d3da4eSJoanne Koong 	if (!dst->data || flags || bpf_dynptr_is_rdonly(dst))
151813bbbfbeSJoanne Koong 		return -EINVAL;
151913bbbfbeSJoanne Koong 
152013bbbfbeSJoanne Koong 	err = bpf_dynptr_check_off_len(dst, offset, len);
152113bbbfbeSJoanne Koong 	if (err)
152213bbbfbeSJoanne Koong 		return err;
152313bbbfbeSJoanne Koong 
152413bbbfbeSJoanne Koong 	memcpy(dst->data + dst->offset + offset, src, len);
152513bbbfbeSJoanne Koong 
152613bbbfbeSJoanne Koong 	return 0;
152713bbbfbeSJoanne Koong }
152813bbbfbeSJoanne Koong 
1529dc368e1cSJoanne Koong static const struct bpf_func_proto bpf_dynptr_write_proto = {
153013bbbfbeSJoanne Koong 	.func		= bpf_dynptr_write,
153113bbbfbeSJoanne Koong 	.gpl_only	= false,
153213bbbfbeSJoanne Koong 	.ret_type	= RET_INTEGER,
153313bbbfbeSJoanne Koong 	.arg1_type	= ARG_PTR_TO_DYNPTR,
153413bbbfbeSJoanne Koong 	.arg2_type	= ARG_ANYTHING,
153513bbbfbeSJoanne Koong 	.arg3_type	= ARG_PTR_TO_MEM | MEM_RDONLY,
153613bbbfbeSJoanne Koong 	.arg4_type	= ARG_CONST_SIZE_OR_ZERO,
1537f8d3da4eSJoanne Koong 	.arg5_type	= ARG_ANYTHING,
153813bbbfbeSJoanne Koong };
153913bbbfbeSJoanne Koong 
154034d4ef57SJoanne Koong BPF_CALL_3(bpf_dynptr_data, struct bpf_dynptr_kern *, ptr, u32, offset, u32, len)
154134d4ef57SJoanne Koong {
154234d4ef57SJoanne Koong 	int err;
154334d4ef57SJoanne Koong 
154434d4ef57SJoanne Koong 	if (!ptr->data)
154534d4ef57SJoanne Koong 		return 0;
154634d4ef57SJoanne Koong 
154734d4ef57SJoanne Koong 	err = bpf_dynptr_check_off_len(ptr, offset, len);
154834d4ef57SJoanne Koong 	if (err)
154934d4ef57SJoanne Koong 		return 0;
155034d4ef57SJoanne Koong 
155134d4ef57SJoanne Koong 	if (bpf_dynptr_is_rdonly(ptr))
155234d4ef57SJoanne Koong 		return 0;
155334d4ef57SJoanne Koong 
155434d4ef57SJoanne Koong 	return (unsigned long)(ptr->data + ptr->offset + offset);
155534d4ef57SJoanne Koong }
155634d4ef57SJoanne Koong 
1557dc368e1cSJoanne Koong static const struct bpf_func_proto bpf_dynptr_data_proto = {
155834d4ef57SJoanne Koong 	.func		= bpf_dynptr_data,
155934d4ef57SJoanne Koong 	.gpl_only	= false,
156034d4ef57SJoanne Koong 	.ret_type	= RET_PTR_TO_DYNPTR_MEM_OR_NULL,
156134d4ef57SJoanne Koong 	.arg1_type	= ARG_PTR_TO_DYNPTR,
156234d4ef57SJoanne Koong 	.arg2_type	= ARG_ANYTHING,
156334d4ef57SJoanne Koong 	.arg3_type	= ARG_CONST_ALLOC_SIZE_OR_ZERO,
156434d4ef57SJoanne Koong };
156534d4ef57SJoanne Koong 
1566f470378cSJohn Fastabend const struct bpf_func_proto bpf_get_current_task_proto __weak;
1567a396eda5SDaniel Xu const struct bpf_func_proto bpf_get_current_task_btf_proto __weak;
1568f470378cSJohn Fastabend const struct bpf_func_proto bpf_probe_read_user_proto __weak;
1569f470378cSJohn Fastabend const struct bpf_func_proto bpf_probe_read_user_str_proto __weak;
1570f470378cSJohn Fastabend const struct bpf_func_proto bpf_probe_read_kernel_proto __weak;
1571f470378cSJohn Fastabend const struct bpf_func_proto bpf_probe_read_kernel_str_proto __weak;
1572dd6e10fbSDaniel Xu const struct bpf_func_proto bpf_task_pt_regs_proto __weak;
1573f470378cSJohn Fastabend 
15746890896bSStanislav Fomichev const struct bpf_func_proto *
15756890896bSStanislav Fomichev bpf_base_func_proto(enum bpf_func_id func_id)
15766890896bSStanislav Fomichev {
15776890896bSStanislav Fomichev 	switch (func_id) {
15786890896bSStanislav Fomichev 	case BPF_FUNC_map_lookup_elem:
15796890896bSStanislav Fomichev 		return &bpf_map_lookup_elem_proto;
15806890896bSStanislav Fomichev 	case BPF_FUNC_map_update_elem:
15816890896bSStanislav Fomichev 		return &bpf_map_update_elem_proto;
15826890896bSStanislav Fomichev 	case BPF_FUNC_map_delete_elem:
15836890896bSStanislav Fomichev 		return &bpf_map_delete_elem_proto;
15846890896bSStanislav Fomichev 	case BPF_FUNC_map_push_elem:
15856890896bSStanislav Fomichev 		return &bpf_map_push_elem_proto;
15866890896bSStanislav Fomichev 	case BPF_FUNC_map_pop_elem:
15876890896bSStanislav Fomichev 		return &bpf_map_pop_elem_proto;
15886890896bSStanislav Fomichev 	case BPF_FUNC_map_peek_elem:
15896890896bSStanislav Fomichev 		return &bpf_map_peek_elem_proto;
159007343110SFeng Zhou 	case BPF_FUNC_map_lookup_percpu_elem:
159107343110SFeng Zhou 		return &bpf_map_lookup_percpu_elem_proto;
15926890896bSStanislav Fomichev 	case BPF_FUNC_get_prandom_u32:
15936890896bSStanislav Fomichev 		return &bpf_get_prandom_u32_proto;
15946890896bSStanislav Fomichev 	case BPF_FUNC_get_smp_processor_id:
15956890896bSStanislav Fomichev 		return &bpf_get_raw_smp_processor_id_proto;
15966890896bSStanislav Fomichev 	case BPF_FUNC_get_numa_node_id:
15976890896bSStanislav Fomichev 		return &bpf_get_numa_node_id_proto;
15986890896bSStanislav Fomichev 	case BPF_FUNC_tail_call:
15996890896bSStanislav Fomichev 		return &bpf_tail_call_proto;
16006890896bSStanislav Fomichev 	case BPF_FUNC_ktime_get_ns:
16016890896bSStanislav Fomichev 		return &bpf_ktime_get_ns_proto;
160271d19214SMaciej Żenczykowski 	case BPF_FUNC_ktime_get_boot_ns:
160371d19214SMaciej Żenczykowski 		return &bpf_ktime_get_boot_ns_proto;
1604c8996c98SJesper Dangaard Brouer 	case BPF_FUNC_ktime_get_tai_ns:
1605c8996c98SJesper Dangaard Brouer 		return &bpf_ktime_get_tai_ns_proto;
1606457f4436SAndrii Nakryiko 	case BPF_FUNC_ringbuf_output:
1607457f4436SAndrii Nakryiko 		return &bpf_ringbuf_output_proto;
1608457f4436SAndrii Nakryiko 	case BPF_FUNC_ringbuf_reserve:
1609457f4436SAndrii Nakryiko 		return &bpf_ringbuf_reserve_proto;
1610457f4436SAndrii Nakryiko 	case BPF_FUNC_ringbuf_submit:
1611457f4436SAndrii Nakryiko 		return &bpf_ringbuf_submit_proto;
1612457f4436SAndrii Nakryiko 	case BPF_FUNC_ringbuf_discard:
1613457f4436SAndrii Nakryiko 		return &bpf_ringbuf_discard_proto;
1614457f4436SAndrii Nakryiko 	case BPF_FUNC_ringbuf_query:
1615457f4436SAndrii Nakryiko 		return &bpf_ringbuf_query_proto;
1616c5fb1993SHou Tao 	case BPF_FUNC_strncmp:
1617c5fb1993SHou Tao 		return &bpf_strncmp_proto;
16188a67f2deSStanislav Fomichev 	case BPF_FUNC_strtol:
16198a67f2deSStanislav Fomichev 		return &bpf_strtol_proto;
16208a67f2deSStanislav Fomichev 	case BPF_FUNC_strtoul:
16218a67f2deSStanislav Fomichev 		return &bpf_strtoul_proto;
16226890896bSStanislav Fomichev 	default:
16236890896bSStanislav Fomichev 		break;
16246890896bSStanislav Fomichev 	}
16256890896bSStanislav Fomichev 
16262c78ee89SAlexei Starovoitov 	if (!bpf_capable())
16276890896bSStanislav Fomichev 		return NULL;
16286890896bSStanislav Fomichev 
16296890896bSStanislav Fomichev 	switch (func_id) {
16306890896bSStanislav Fomichev 	case BPF_FUNC_spin_lock:
16316890896bSStanislav Fomichev 		return &bpf_spin_lock_proto;
16326890896bSStanislav Fomichev 	case BPF_FUNC_spin_unlock:
16336890896bSStanislav Fomichev 		return &bpf_spin_unlock_proto;
16346890896bSStanislav Fomichev 	case BPF_FUNC_jiffies64:
16356890896bSStanislav Fomichev 		return &bpf_jiffies64_proto;
1636b7906b70SAndrii Nakryiko 	case BPF_FUNC_per_cpu_ptr:
1637eaa6bcb7SHao Luo 		return &bpf_per_cpu_ptr_proto;
1638b7906b70SAndrii Nakryiko 	case BPF_FUNC_this_cpu_ptr:
163963d9b80dSHao Luo 		return &bpf_this_cpu_ptr_proto;
1640b00628b1SAlexei Starovoitov 	case BPF_FUNC_timer_init:
1641b00628b1SAlexei Starovoitov 		return &bpf_timer_init_proto;
1642b00628b1SAlexei Starovoitov 	case BPF_FUNC_timer_set_callback:
1643b00628b1SAlexei Starovoitov 		return &bpf_timer_set_callback_proto;
1644b00628b1SAlexei Starovoitov 	case BPF_FUNC_timer_start:
1645b00628b1SAlexei Starovoitov 		return &bpf_timer_start_proto;
1646b00628b1SAlexei Starovoitov 	case BPF_FUNC_timer_cancel:
1647b00628b1SAlexei Starovoitov 		return &bpf_timer_cancel_proto;
1648c0a5a21cSKumar Kartikeya Dwivedi 	case BPF_FUNC_kptr_xchg:
1649c0a5a21cSKumar Kartikeya Dwivedi 		return &bpf_kptr_xchg_proto;
16505679ff2fSKumar Kartikeya Dwivedi 	case BPF_FUNC_for_each_map_elem:
16515679ff2fSKumar Kartikeya Dwivedi 		return &bpf_for_each_map_elem_proto;
16525679ff2fSKumar Kartikeya Dwivedi 	case BPF_FUNC_loop:
16535679ff2fSKumar Kartikeya Dwivedi 		return &bpf_loop_proto;
165420571567SDavid Vernet 	case BPF_FUNC_user_ringbuf_drain:
165520571567SDavid Vernet 		return &bpf_user_ringbuf_drain_proto;
16568addbfc7SKumar Kartikeya Dwivedi 	case BPF_FUNC_ringbuf_reserve_dynptr:
16578addbfc7SKumar Kartikeya Dwivedi 		return &bpf_ringbuf_reserve_dynptr_proto;
16588addbfc7SKumar Kartikeya Dwivedi 	case BPF_FUNC_ringbuf_submit_dynptr:
16598addbfc7SKumar Kartikeya Dwivedi 		return &bpf_ringbuf_submit_dynptr_proto;
16608addbfc7SKumar Kartikeya Dwivedi 	case BPF_FUNC_ringbuf_discard_dynptr:
16618addbfc7SKumar Kartikeya Dwivedi 		return &bpf_ringbuf_discard_dynptr_proto;
16628addbfc7SKumar Kartikeya Dwivedi 	case BPF_FUNC_dynptr_from_mem:
16638addbfc7SKumar Kartikeya Dwivedi 		return &bpf_dynptr_from_mem_proto;
16648addbfc7SKumar Kartikeya Dwivedi 	case BPF_FUNC_dynptr_read:
16658addbfc7SKumar Kartikeya Dwivedi 		return &bpf_dynptr_read_proto;
16668addbfc7SKumar Kartikeya Dwivedi 	case BPF_FUNC_dynptr_write:
16678addbfc7SKumar Kartikeya Dwivedi 		return &bpf_dynptr_write_proto;
16688addbfc7SKumar Kartikeya Dwivedi 	case BPF_FUNC_dynptr_data:
16698addbfc7SKumar Kartikeya Dwivedi 		return &bpf_dynptr_data_proto;
1670c4bcfb38SYonghong Song #ifdef CONFIG_CGROUPS
1671c4bcfb38SYonghong Song 	case BPF_FUNC_cgrp_storage_get:
1672c4bcfb38SYonghong Song 		return &bpf_cgrp_storage_get_proto;
1673c4bcfb38SYonghong Song 	case BPF_FUNC_cgrp_storage_delete:
1674c4bcfb38SYonghong Song 		return &bpf_cgrp_storage_delete_proto;
1675c4bcfb38SYonghong Song #endif
16766890896bSStanislav Fomichev 	default:
1677f470378cSJohn Fastabend 		break;
1678f470378cSJohn Fastabend 	}
1679f470378cSJohn Fastabend 
1680f470378cSJohn Fastabend 	if (!perfmon_capable())
1681f470378cSJohn Fastabend 		return NULL;
1682f470378cSJohn Fastabend 
1683f470378cSJohn Fastabend 	switch (func_id) {
168461ca36c8STobias Klauser 	case BPF_FUNC_trace_printk:
168561ca36c8STobias Klauser 		return bpf_get_trace_printk_proto();
1686f470378cSJohn Fastabend 	case BPF_FUNC_get_current_task:
1687f470378cSJohn Fastabend 		return &bpf_get_current_task_proto;
1688a396eda5SDaniel Xu 	case BPF_FUNC_get_current_task_btf:
1689a396eda5SDaniel Xu 		return &bpf_get_current_task_btf_proto;
1690f470378cSJohn Fastabend 	case BPF_FUNC_probe_read_user:
1691f470378cSJohn Fastabend 		return &bpf_probe_read_user_proto;
1692f470378cSJohn Fastabend 	case BPF_FUNC_probe_read_kernel:
169371330842SDaniel Borkmann 		return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
1694ff40e510SDaniel Borkmann 		       NULL : &bpf_probe_read_kernel_proto;
1695f470378cSJohn Fastabend 	case BPF_FUNC_probe_read_user_str:
1696f470378cSJohn Fastabend 		return &bpf_probe_read_user_str_proto;
1697f470378cSJohn Fastabend 	case BPF_FUNC_probe_read_kernel_str:
169871330842SDaniel Borkmann 		return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
1699ff40e510SDaniel Borkmann 		       NULL : &bpf_probe_read_kernel_str_proto;
170061ca36c8STobias Klauser 	case BPF_FUNC_snprintf_btf:
170161ca36c8STobias Klauser 		return &bpf_snprintf_btf_proto;
17027b15523aSFlorent Revest 	case BPF_FUNC_snprintf:
17037b15523aSFlorent Revest 		return &bpf_snprintf_proto;
1704dd6e10fbSDaniel Xu 	case BPF_FUNC_task_pt_regs:
1705dd6e10fbSDaniel Xu 		return &bpf_task_pt_regs_proto;
170610aceb62SDave Marchevsky 	case BPF_FUNC_trace_vprintk:
170710aceb62SDave Marchevsky 		return bpf_get_trace_vprintk_proto();
1708f470378cSJohn Fastabend 	default:
17096890896bSStanislav Fomichev 		return NULL;
17106890896bSStanislav Fomichev 	}
17116890896bSStanislav Fomichev }
171213379059SArtem Savkov 
1713f0c5941fSKumar Kartikeya Dwivedi void bpf_list_head_free(const struct btf_field *field, void *list_head,
1714f0c5941fSKumar Kartikeya Dwivedi 			struct bpf_spin_lock *spin_lock)
1715f0c5941fSKumar Kartikeya Dwivedi {
1716f0c5941fSKumar Kartikeya Dwivedi 	struct list_head *head = list_head, *orig_head = list_head;
1717f0c5941fSKumar Kartikeya Dwivedi 
1718f0c5941fSKumar Kartikeya Dwivedi 	BUILD_BUG_ON(sizeof(struct list_head) > sizeof(struct bpf_list_head));
1719f0c5941fSKumar Kartikeya Dwivedi 	BUILD_BUG_ON(__alignof__(struct list_head) > __alignof__(struct bpf_list_head));
1720f0c5941fSKumar Kartikeya Dwivedi 
1721f0c5941fSKumar Kartikeya Dwivedi 	/* Do the actual list draining outside the lock to not hold the lock for
1722f0c5941fSKumar Kartikeya Dwivedi 	 * too long, and also prevent deadlocks if tracing programs end up
1723f0c5941fSKumar Kartikeya Dwivedi 	 * executing on entry/exit of functions called inside the critical
1724f0c5941fSKumar Kartikeya Dwivedi 	 * section, and end up doing map ops that call bpf_list_head_free for
1725f0c5941fSKumar Kartikeya Dwivedi 	 * the same map value again.
1726f0c5941fSKumar Kartikeya Dwivedi 	 */
1727f0c5941fSKumar Kartikeya Dwivedi 	__bpf_spin_lock_irqsave(spin_lock);
1728f0c5941fSKumar Kartikeya Dwivedi 	if (!head->next || list_empty(head))
1729f0c5941fSKumar Kartikeya Dwivedi 		goto unlock;
1730f0c5941fSKumar Kartikeya Dwivedi 	head = head->next;
1731f0c5941fSKumar Kartikeya Dwivedi unlock:
1732f0c5941fSKumar Kartikeya Dwivedi 	INIT_LIST_HEAD(orig_head);
1733f0c5941fSKumar Kartikeya Dwivedi 	__bpf_spin_unlock_irqrestore(spin_lock);
1734f0c5941fSKumar Kartikeya Dwivedi 
1735f0c5941fSKumar Kartikeya Dwivedi 	while (head != orig_head) {
1736f0c5941fSKumar Kartikeya Dwivedi 		void *obj = head;
1737f0c5941fSKumar Kartikeya Dwivedi 
1738f0c5941fSKumar Kartikeya Dwivedi 		obj -= field->list_head.node_offset;
1739f0c5941fSKumar Kartikeya Dwivedi 		head = head->next;
1740958cf2e2SKumar Kartikeya Dwivedi 		/* The contained type can also have resources, including a
1741958cf2e2SKumar Kartikeya Dwivedi 		 * bpf_list_head which needs to be freed.
1742958cf2e2SKumar Kartikeya Dwivedi 		 */
1743958cf2e2SKumar Kartikeya Dwivedi 		bpf_obj_free_fields(field->list_head.value_rec, obj);
1744958cf2e2SKumar Kartikeya Dwivedi 		/* bpf_mem_free requires migrate_disable(), since we can be
1745958cf2e2SKumar Kartikeya Dwivedi 		 * called from map free path as well apart from BPF program (as
1746958cf2e2SKumar Kartikeya Dwivedi 		 * part of map ops doing bpf_obj_free_fields).
1747958cf2e2SKumar Kartikeya Dwivedi 		 */
1748958cf2e2SKumar Kartikeya Dwivedi 		migrate_disable();
1749958cf2e2SKumar Kartikeya Dwivedi 		bpf_mem_free(&bpf_global_ma, obj);
1750958cf2e2SKumar Kartikeya Dwivedi 		migrate_enable();
1751f0c5941fSKumar Kartikeya Dwivedi 	}
1752f0c5941fSKumar Kartikeya Dwivedi }
1753f0c5941fSKumar Kartikeya Dwivedi 
1754958cf2e2SKumar Kartikeya Dwivedi __diag_push();
1755958cf2e2SKumar Kartikeya Dwivedi __diag_ignore_all("-Wmissing-prototypes",
1756958cf2e2SKumar Kartikeya Dwivedi 		  "Global functions as their definitions will be in vmlinux BTF");
1757958cf2e2SKumar Kartikeya Dwivedi 
1758958cf2e2SKumar Kartikeya Dwivedi void *bpf_obj_new_impl(u64 local_type_id__k, void *meta__ign)
1759958cf2e2SKumar Kartikeya Dwivedi {
1760958cf2e2SKumar Kartikeya Dwivedi 	struct btf_struct_meta *meta = meta__ign;
1761958cf2e2SKumar Kartikeya Dwivedi 	u64 size = local_type_id__k;
1762958cf2e2SKumar Kartikeya Dwivedi 	void *p;
1763958cf2e2SKumar Kartikeya Dwivedi 
1764958cf2e2SKumar Kartikeya Dwivedi 	p = bpf_mem_alloc(&bpf_global_ma, size);
1765958cf2e2SKumar Kartikeya Dwivedi 	if (!p)
1766958cf2e2SKumar Kartikeya Dwivedi 		return NULL;
1767958cf2e2SKumar Kartikeya Dwivedi 	if (meta)
1768958cf2e2SKumar Kartikeya Dwivedi 		bpf_obj_init(meta->field_offs, p);
1769958cf2e2SKumar Kartikeya Dwivedi 	return p;
1770958cf2e2SKumar Kartikeya Dwivedi }
1771958cf2e2SKumar Kartikeya Dwivedi 
1772ac9f0605SKumar Kartikeya Dwivedi void bpf_obj_drop_impl(void *p__alloc, void *meta__ign)
1773ac9f0605SKumar Kartikeya Dwivedi {
1774ac9f0605SKumar Kartikeya Dwivedi 	struct btf_struct_meta *meta = meta__ign;
1775ac9f0605SKumar Kartikeya Dwivedi 	void *p = p__alloc;
1776ac9f0605SKumar Kartikeya Dwivedi 
1777ac9f0605SKumar Kartikeya Dwivedi 	if (meta)
1778ac9f0605SKumar Kartikeya Dwivedi 		bpf_obj_free_fields(meta->record, p);
1779ac9f0605SKumar Kartikeya Dwivedi 	bpf_mem_free(&bpf_global_ma, p);
1780ac9f0605SKumar Kartikeya Dwivedi }
1781ac9f0605SKumar Kartikeya Dwivedi 
17828cab76ecSKumar Kartikeya Dwivedi static void __bpf_list_add(struct bpf_list_node *node, struct bpf_list_head *head, bool tail)
17838cab76ecSKumar Kartikeya Dwivedi {
17848cab76ecSKumar Kartikeya Dwivedi 	struct list_head *n = (void *)node, *h = (void *)head;
17858cab76ecSKumar Kartikeya Dwivedi 
17868cab76ecSKumar Kartikeya Dwivedi 	if (unlikely(!h->next))
17878cab76ecSKumar Kartikeya Dwivedi 		INIT_LIST_HEAD(h);
17888cab76ecSKumar Kartikeya Dwivedi 	if (unlikely(!n->next))
17898cab76ecSKumar Kartikeya Dwivedi 		INIT_LIST_HEAD(n);
17908cab76ecSKumar Kartikeya Dwivedi 	tail ? list_add_tail(n, h) : list_add(n, h);
17918cab76ecSKumar Kartikeya Dwivedi }
17928cab76ecSKumar Kartikeya Dwivedi 
17938cab76ecSKumar Kartikeya Dwivedi void bpf_list_push_front(struct bpf_list_head *head, struct bpf_list_node *node)
17948cab76ecSKumar Kartikeya Dwivedi {
17958cab76ecSKumar Kartikeya Dwivedi 	return __bpf_list_add(node, head, false);
17968cab76ecSKumar Kartikeya Dwivedi }
17978cab76ecSKumar Kartikeya Dwivedi 
17988cab76ecSKumar Kartikeya Dwivedi void bpf_list_push_back(struct bpf_list_head *head, struct bpf_list_node *node)
17998cab76ecSKumar Kartikeya Dwivedi {
18008cab76ecSKumar Kartikeya Dwivedi 	return __bpf_list_add(node, head, true);
18018cab76ecSKumar Kartikeya Dwivedi }
18028cab76ecSKumar Kartikeya Dwivedi 
18038cab76ecSKumar Kartikeya Dwivedi static struct bpf_list_node *__bpf_list_del(struct bpf_list_head *head, bool tail)
18048cab76ecSKumar Kartikeya Dwivedi {
18058cab76ecSKumar Kartikeya Dwivedi 	struct list_head *n, *h = (void *)head;
18068cab76ecSKumar Kartikeya Dwivedi 
18078cab76ecSKumar Kartikeya Dwivedi 	if (unlikely(!h->next))
18088cab76ecSKumar Kartikeya Dwivedi 		INIT_LIST_HEAD(h);
18098cab76ecSKumar Kartikeya Dwivedi 	if (list_empty(h))
18108cab76ecSKumar Kartikeya Dwivedi 		return NULL;
18118cab76ecSKumar Kartikeya Dwivedi 	n = tail ? h->prev : h->next;
18128cab76ecSKumar Kartikeya Dwivedi 	list_del_init(n);
18138cab76ecSKumar Kartikeya Dwivedi 	return (struct bpf_list_node *)n;
18148cab76ecSKumar Kartikeya Dwivedi }
18158cab76ecSKumar Kartikeya Dwivedi 
18168cab76ecSKumar Kartikeya Dwivedi struct bpf_list_node *bpf_list_pop_front(struct bpf_list_head *head)
18178cab76ecSKumar Kartikeya Dwivedi {
18188cab76ecSKumar Kartikeya Dwivedi 	return __bpf_list_del(head, false);
18198cab76ecSKumar Kartikeya Dwivedi }
18208cab76ecSKumar Kartikeya Dwivedi 
18218cab76ecSKumar Kartikeya Dwivedi struct bpf_list_node *bpf_list_pop_back(struct bpf_list_head *head)
18228cab76ecSKumar Kartikeya Dwivedi {
18238cab76ecSKumar Kartikeya Dwivedi 	return __bpf_list_del(head, true);
18248cab76ecSKumar Kartikeya Dwivedi }
18258cab76ecSKumar Kartikeya Dwivedi 
182690660309SDavid Vernet /**
182790660309SDavid Vernet  * bpf_task_acquire - Acquire a reference to a task. A task acquired by this
182890660309SDavid Vernet  * kfunc which is not stored in a map as a kptr, must be released by calling
182990660309SDavid Vernet  * bpf_task_release().
183090660309SDavid Vernet  * @p: The task on which a reference is being acquired.
183190660309SDavid Vernet  */
183290660309SDavid Vernet struct task_struct *bpf_task_acquire(struct task_struct *p)
183390660309SDavid Vernet {
183490660309SDavid Vernet 	refcount_inc(&p->rcu_users);
183590660309SDavid Vernet 	return p;
183690660309SDavid Vernet }
183790660309SDavid Vernet 
183890660309SDavid Vernet /**
183990660309SDavid Vernet  * bpf_task_kptr_get - Acquire a reference on a struct task_struct kptr. A task
184090660309SDavid Vernet  * kptr acquired by this kfunc which is not subsequently stored in a map, must
184190660309SDavid Vernet  * be released by calling bpf_task_release().
184290660309SDavid Vernet  * @pp: A pointer to a task kptr on which a reference is being acquired.
184390660309SDavid Vernet  */
184490660309SDavid Vernet struct task_struct *bpf_task_kptr_get(struct task_struct **pp)
184590660309SDavid Vernet {
184690660309SDavid Vernet 	struct task_struct *p;
184790660309SDavid Vernet 
184890660309SDavid Vernet 	rcu_read_lock();
184990660309SDavid Vernet 	p = READ_ONCE(*pp);
185090660309SDavid Vernet 
185190660309SDavid Vernet 	/* Another context could remove the task from the map and release it at
185290660309SDavid Vernet 	 * any time, including after we've done the lookup above. This is safe
185390660309SDavid Vernet 	 * because we're in an RCU read region, so the task is guaranteed to
185490660309SDavid Vernet 	 * remain valid until at least the rcu_read_unlock() below.
185590660309SDavid Vernet 	 */
185690660309SDavid Vernet 	if (p && !refcount_inc_not_zero(&p->rcu_users))
185790660309SDavid Vernet 		/* If the task had been removed from the map and freed as
185890660309SDavid Vernet 		 * described above, refcount_inc_not_zero() will return false.
185990660309SDavid Vernet 		 * The task will be freed at some point after the current RCU
186090660309SDavid Vernet 		 * gp has ended, so just return NULL to the user.
186190660309SDavid Vernet 		 */
186290660309SDavid Vernet 		p = NULL;
186390660309SDavid Vernet 	rcu_read_unlock();
186490660309SDavid Vernet 
186590660309SDavid Vernet 	return p;
186690660309SDavid Vernet }
186790660309SDavid Vernet 
186890660309SDavid Vernet /**
186990660309SDavid Vernet  * bpf_task_release - Release the reference acquired on a struct task_struct *.
187090660309SDavid Vernet  * If this kfunc is invoked in an RCU read region, the task_struct is
187190660309SDavid Vernet  * guaranteed to not be freed until the current grace period has ended, even if
187290660309SDavid Vernet  * its refcount drops to 0.
187390660309SDavid Vernet  * @p: The task on which a reference is being released.
187490660309SDavid Vernet  */
187590660309SDavid Vernet void bpf_task_release(struct task_struct *p)
187690660309SDavid Vernet {
187790660309SDavid Vernet 	if (!p)
187890660309SDavid Vernet 		return;
187990660309SDavid Vernet 
188090660309SDavid Vernet 	put_task_struct_rcu_user(p);
188190660309SDavid Vernet }
188290660309SDavid Vernet 
1883fda01efcSDavid Vernet #ifdef CONFIG_CGROUPS
1884fda01efcSDavid Vernet /**
1885fda01efcSDavid Vernet  * bpf_cgroup_acquire - Acquire a reference to a cgroup. A cgroup acquired by
1886fda01efcSDavid Vernet  * this kfunc which is not stored in a map as a kptr, must be released by
1887fda01efcSDavid Vernet  * calling bpf_cgroup_release().
1888fda01efcSDavid Vernet  * @cgrp: The cgroup on which a reference is being acquired.
1889fda01efcSDavid Vernet  */
1890fda01efcSDavid Vernet struct cgroup *bpf_cgroup_acquire(struct cgroup *cgrp)
1891fda01efcSDavid Vernet {
1892fda01efcSDavid Vernet 	cgroup_get(cgrp);
1893fda01efcSDavid Vernet 	return cgrp;
1894fda01efcSDavid Vernet }
1895fda01efcSDavid Vernet 
1896fda01efcSDavid Vernet /**
1897fda01efcSDavid Vernet  * bpf_cgroup_kptr_get - Acquire a reference on a struct cgroup kptr. A cgroup
1898fda01efcSDavid Vernet  * kptr acquired by this kfunc which is not subsequently stored in a map, must
1899fda01efcSDavid Vernet  * be released by calling bpf_cgroup_release().
1900fda01efcSDavid Vernet  * @cgrpp: A pointer to a cgroup kptr on which a reference is being acquired.
1901fda01efcSDavid Vernet  */
1902fda01efcSDavid Vernet struct cgroup *bpf_cgroup_kptr_get(struct cgroup **cgrpp)
1903fda01efcSDavid Vernet {
1904fda01efcSDavid Vernet 	struct cgroup *cgrp;
1905fda01efcSDavid Vernet 
1906fda01efcSDavid Vernet 	rcu_read_lock();
1907fda01efcSDavid Vernet 	/* Another context could remove the cgroup from the map and release it
1908fda01efcSDavid Vernet 	 * at any time, including after we've done the lookup above. This is
1909fda01efcSDavid Vernet 	 * safe because we're in an RCU read region, so the cgroup is
1910fda01efcSDavid Vernet 	 * guaranteed to remain valid until at least the rcu_read_unlock()
1911fda01efcSDavid Vernet 	 * below.
1912fda01efcSDavid Vernet 	 */
1913fda01efcSDavid Vernet 	cgrp = READ_ONCE(*cgrpp);
1914fda01efcSDavid Vernet 
1915fda01efcSDavid Vernet 	if (cgrp && !cgroup_tryget(cgrp))
1916fda01efcSDavid Vernet 		/* If the cgroup had been removed from the map and freed as
1917fda01efcSDavid Vernet 		 * described above, cgroup_tryget() will return false. The
1918fda01efcSDavid Vernet 		 * cgroup will be freed at some point after the current RCU gp
1919fda01efcSDavid Vernet 		 * has ended, so just return NULL to the user.
1920fda01efcSDavid Vernet 		 */
1921fda01efcSDavid Vernet 		cgrp = NULL;
1922fda01efcSDavid Vernet 	rcu_read_unlock();
1923fda01efcSDavid Vernet 
1924fda01efcSDavid Vernet 	return cgrp;
1925fda01efcSDavid Vernet }
1926fda01efcSDavid Vernet 
1927fda01efcSDavid Vernet /**
1928fda01efcSDavid Vernet  * bpf_cgroup_release - Release the reference acquired on a struct cgroup *.
1929fda01efcSDavid Vernet  * If this kfunc is invoked in an RCU read region, the cgroup is guaranteed to
1930fda01efcSDavid Vernet  * not be freed until the current grace period has ended, even if its refcount
1931fda01efcSDavid Vernet  * drops to 0.
1932fda01efcSDavid Vernet  * @cgrp: The cgroup on which a reference is being released.
1933fda01efcSDavid Vernet  */
1934fda01efcSDavid Vernet void bpf_cgroup_release(struct cgroup *cgrp)
1935fda01efcSDavid Vernet {
1936fda01efcSDavid Vernet 	if (!cgrp)
1937fda01efcSDavid Vernet 		return;
1938fda01efcSDavid Vernet 
1939fda01efcSDavid Vernet 	cgroup_put(cgrp);
1940fda01efcSDavid Vernet }
1941*5ca78670SDavid Vernet 
1942*5ca78670SDavid Vernet /**
1943*5ca78670SDavid Vernet  * bpf_cgroup_ancestor - Perform a lookup on an entry in a cgroup's ancestor
1944*5ca78670SDavid Vernet  * array. A cgroup returned by this kfunc which is not subsequently stored in a
1945*5ca78670SDavid Vernet  * map, must be released by calling bpf_cgroup_release().
1946*5ca78670SDavid Vernet  * @cgrp: The cgroup for which we're performing a lookup.
1947*5ca78670SDavid Vernet  * @level: The level of ancestor to look up.
1948*5ca78670SDavid Vernet  */
1949*5ca78670SDavid Vernet struct cgroup *bpf_cgroup_ancestor(struct cgroup *cgrp, int level)
1950*5ca78670SDavid Vernet {
1951*5ca78670SDavid Vernet 	struct cgroup *ancestor;
1952*5ca78670SDavid Vernet 
1953*5ca78670SDavid Vernet 	if (level > cgrp->level || level < 0)
1954*5ca78670SDavid Vernet 		return NULL;
1955*5ca78670SDavid Vernet 
1956*5ca78670SDavid Vernet 	ancestor = cgrp->ancestors[level];
1957*5ca78670SDavid Vernet 	cgroup_get(ancestor);
1958*5ca78670SDavid Vernet 	return ancestor;
1959*5ca78670SDavid Vernet }
1960fda01efcSDavid Vernet #endif /* CONFIG_CGROUPS */
1961fda01efcSDavid Vernet 
1962fd264ca0SYonghong Song void *bpf_cast_to_kern_ctx(void *obj)
1963fd264ca0SYonghong Song {
1964fd264ca0SYonghong Song 	return obj;
1965fd264ca0SYonghong Song }
1966fd264ca0SYonghong Song 
1967a35b9af4SYonghong Song void *bpf_rdonly_cast(void *obj__ign, u32 btf_id__k)
1968a35b9af4SYonghong Song {
1969a35b9af4SYonghong Song 	return obj__ign;
1970a35b9af4SYonghong Song }
1971a35b9af4SYonghong Song 
1972958cf2e2SKumar Kartikeya Dwivedi __diag_pop();
1973958cf2e2SKumar Kartikeya Dwivedi 
1974958cf2e2SKumar Kartikeya Dwivedi BTF_SET8_START(generic_btf_ids)
197513379059SArtem Savkov #ifdef CONFIG_KEXEC_CORE
197613379059SArtem Savkov BTF_ID_FLAGS(func, crash_kexec, KF_DESTRUCTIVE)
197713379059SArtem Savkov #endif
1978958cf2e2SKumar Kartikeya Dwivedi BTF_ID_FLAGS(func, bpf_obj_new_impl, KF_ACQUIRE | KF_RET_NULL)
1979ac9f0605SKumar Kartikeya Dwivedi BTF_ID_FLAGS(func, bpf_obj_drop_impl, KF_RELEASE)
19808cab76ecSKumar Kartikeya Dwivedi BTF_ID_FLAGS(func, bpf_list_push_front)
19818cab76ecSKumar Kartikeya Dwivedi BTF_ID_FLAGS(func, bpf_list_push_back)
19828cab76ecSKumar Kartikeya Dwivedi BTF_ID_FLAGS(func, bpf_list_pop_front, KF_ACQUIRE | KF_RET_NULL)
19838cab76ecSKumar Kartikeya Dwivedi BTF_ID_FLAGS(func, bpf_list_pop_back, KF_ACQUIRE | KF_RET_NULL)
198490660309SDavid Vernet BTF_ID_FLAGS(func, bpf_task_acquire, KF_ACQUIRE | KF_TRUSTED_ARGS)
198590660309SDavid Vernet BTF_ID_FLAGS(func, bpf_task_kptr_get, KF_ACQUIRE | KF_KPTR_GET | KF_RET_NULL)
198690660309SDavid Vernet BTF_ID_FLAGS(func, bpf_task_release, KF_RELEASE)
1987fda01efcSDavid Vernet 
1988fda01efcSDavid Vernet #ifdef CONFIG_CGROUPS
1989fda01efcSDavid Vernet BTF_ID_FLAGS(func, bpf_cgroup_acquire, KF_ACQUIRE | KF_TRUSTED_ARGS)
1990fda01efcSDavid Vernet BTF_ID_FLAGS(func, bpf_cgroup_kptr_get, KF_ACQUIRE | KF_KPTR_GET | KF_RET_NULL)
1991fda01efcSDavid Vernet BTF_ID_FLAGS(func, bpf_cgroup_release, KF_RELEASE)
1992*5ca78670SDavid Vernet BTF_ID_FLAGS(func, bpf_cgroup_ancestor, KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL)
1993fda01efcSDavid Vernet #endif
1994958cf2e2SKumar Kartikeya Dwivedi BTF_SET8_END(generic_btf_ids)
199513379059SArtem Savkov 
1996958cf2e2SKumar Kartikeya Dwivedi static const struct btf_kfunc_id_set generic_kfunc_set = {
199713379059SArtem Savkov 	.owner = THIS_MODULE,
1998958cf2e2SKumar Kartikeya Dwivedi 	.set   = &generic_btf_ids,
199913379059SArtem Savkov };
200013379059SArtem Savkov 
2001cfe14564SYonghong Song 
200290660309SDavid Vernet BTF_ID_LIST(generic_dtor_ids)
200390660309SDavid Vernet BTF_ID(struct, task_struct)
200490660309SDavid Vernet BTF_ID(func, bpf_task_release)
2005fda01efcSDavid Vernet #ifdef CONFIG_CGROUPS
2006fda01efcSDavid Vernet BTF_ID(struct, cgroup)
2007fda01efcSDavid Vernet BTF_ID(func, bpf_cgroup_release)
2008fda01efcSDavid Vernet #endif
200990660309SDavid Vernet 
2010cfe14564SYonghong Song BTF_SET8_START(common_btf_ids)
2011fd264ca0SYonghong Song BTF_ID_FLAGS(func, bpf_cast_to_kern_ctx)
2012a35b9af4SYonghong Song BTF_ID_FLAGS(func, bpf_rdonly_cast)
2013cfe14564SYonghong Song BTF_SET8_END(common_btf_ids)
2014cfe14564SYonghong Song 
2015cfe14564SYonghong Song static const struct btf_kfunc_id_set common_kfunc_set = {
2016cfe14564SYonghong Song 	.owner = THIS_MODULE,
2017cfe14564SYonghong Song 	.set   = &common_btf_ids,
2018cfe14564SYonghong Song };
2019cfe14564SYonghong Song 
202013379059SArtem Savkov static int __init kfunc_init(void)
202113379059SArtem Savkov {
2022fda01efcSDavid Vernet 	int ret, idx = 0;
202390660309SDavid Vernet 	const struct btf_id_dtor_kfunc generic_dtors[] = {
202490660309SDavid Vernet 		{
2025fda01efcSDavid Vernet 			.btf_id       = generic_dtor_ids[idx++],
2026fda01efcSDavid Vernet 			.kfunc_btf_id = generic_dtor_ids[idx++]
202790660309SDavid Vernet 		},
2028fda01efcSDavid Vernet #ifdef CONFIG_CGROUPS
2029fda01efcSDavid Vernet 		{
2030fda01efcSDavid Vernet 			.btf_id       = generic_dtor_ids[idx++],
2031fda01efcSDavid Vernet 			.kfunc_btf_id = generic_dtor_ids[idx++]
2032fda01efcSDavid Vernet 		},
2033fda01efcSDavid Vernet #endif
203490660309SDavid Vernet 	};
20358cab76ecSKumar Kartikeya Dwivedi 
20368cab76ecSKumar Kartikeya Dwivedi 	ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &generic_kfunc_set);
203790660309SDavid Vernet 	ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &generic_kfunc_set);
203890660309SDavid Vernet 	ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, &generic_kfunc_set);
2039cfe14564SYonghong Song 	ret = ret ?: register_btf_id_dtor_kfuncs(generic_dtors,
204090660309SDavid Vernet 						  ARRAY_SIZE(generic_dtors),
204190660309SDavid Vernet 						  THIS_MODULE);
2042cfe14564SYonghong Song 	return ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_UNSPEC, &common_kfunc_set);
204313379059SArtem Savkov }
204413379059SArtem Savkov 
204513379059SArtem Savkov late_initcall(kfunc_init);
2046