xref: /openbmc/linux/kernel/bpf/helpers.c (revision 34d3a78c681e8e7844b43d1a2f4671a04249c821)
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>
5aef2fedaSJakub Kicinski #include <linux/bpf-cgroup.h>
6d0003ec0SAlexei Starovoitov #include <linux/rcupdate.h>
703e69b50SDaniel Borkmann #include <linux/random.h>
8c04167ceSDaniel Borkmann #include <linux/smp.h>
92d0e30c3SDaniel Borkmann #include <linux/topology.h>
1017ca8cbfSDaniel Borkmann #include <linux/ktime.h>
11ffeedafbSAlexei Starovoitov #include <linux/sched.h>
12ffeedafbSAlexei Starovoitov #include <linux/uidgid.h>
13f3694e00SDaniel Borkmann #include <linux/filter.h>
14d7a4cb9bSAndrey Ignatov #include <linux/ctype.h>
155576b991SMartin KaFai Lau #include <linux/jiffies.h>
16b4490c5cSCarlos Neira #include <linux/pid_namespace.h>
17b4490c5cSCarlos Neira #include <linux/proc_ns.h>
18ff40e510SDaniel Borkmann #include <linux/security.h>
19d7a4cb9bSAndrey Ignatov 
20d7a4cb9bSAndrey Ignatov #include "../../lib/kstrtox.h"
21d0003ec0SAlexei Starovoitov 
22d0003ec0SAlexei Starovoitov /* If kernel subsystem is allowing eBPF programs to call this function,
23d0003ec0SAlexei Starovoitov  * inside its own verifier_ops->get_func_proto() callback it should return
24d0003ec0SAlexei Starovoitov  * bpf_map_lookup_elem_proto, so that verifier can properly check the arguments
25d0003ec0SAlexei Starovoitov  *
26d0003ec0SAlexei Starovoitov  * Different map implementations will rely on rcu in map methods
27d0003ec0SAlexei Starovoitov  * lookup/update/delete, therefore eBPF programs must run under rcu lock
28d0003ec0SAlexei Starovoitov  * if program is allowed to access maps, so check rcu_read_lock_held in
29d0003ec0SAlexei Starovoitov  * all three functions.
30d0003ec0SAlexei Starovoitov  */
31f3694e00SDaniel Borkmann BPF_CALL_2(bpf_map_lookup_elem, struct bpf_map *, map, void *, key)
32d0003ec0SAlexei Starovoitov {
33694cea39SToke Høiland-Jørgensen 	WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
34f3694e00SDaniel Borkmann 	return (unsigned long) map->ops->map_lookup_elem(map, key);
35d0003ec0SAlexei Starovoitov }
36d0003ec0SAlexei Starovoitov 
37a2c83fffSDaniel Borkmann const struct bpf_func_proto bpf_map_lookup_elem_proto = {
38d0003ec0SAlexei Starovoitov 	.func		= bpf_map_lookup_elem,
39d0003ec0SAlexei Starovoitov 	.gpl_only	= false,
4036bbef52SDaniel Borkmann 	.pkt_access	= true,
41d0003ec0SAlexei Starovoitov 	.ret_type	= RET_PTR_TO_MAP_VALUE_OR_NULL,
42d0003ec0SAlexei Starovoitov 	.arg1_type	= ARG_CONST_MAP_PTR,
43d0003ec0SAlexei Starovoitov 	.arg2_type	= ARG_PTR_TO_MAP_KEY,
44d0003ec0SAlexei Starovoitov };
45d0003ec0SAlexei Starovoitov 
46f3694e00SDaniel Borkmann BPF_CALL_4(bpf_map_update_elem, struct bpf_map *, map, void *, key,
47f3694e00SDaniel Borkmann 	   void *, value, u64, flags)
48d0003ec0SAlexei Starovoitov {
49694cea39SToke Høiland-Jørgensen 	WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
50f3694e00SDaniel Borkmann 	return map->ops->map_update_elem(map, key, value, flags);
51d0003ec0SAlexei Starovoitov }
52d0003ec0SAlexei Starovoitov 
53a2c83fffSDaniel Borkmann const struct bpf_func_proto bpf_map_update_elem_proto = {
54d0003ec0SAlexei Starovoitov 	.func		= bpf_map_update_elem,
55d0003ec0SAlexei Starovoitov 	.gpl_only	= false,
5636bbef52SDaniel Borkmann 	.pkt_access	= true,
57d0003ec0SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
58d0003ec0SAlexei Starovoitov 	.arg1_type	= ARG_CONST_MAP_PTR,
59d0003ec0SAlexei Starovoitov 	.arg2_type	= ARG_PTR_TO_MAP_KEY,
60d0003ec0SAlexei Starovoitov 	.arg3_type	= ARG_PTR_TO_MAP_VALUE,
61d0003ec0SAlexei Starovoitov 	.arg4_type	= ARG_ANYTHING,
62d0003ec0SAlexei Starovoitov };
63d0003ec0SAlexei Starovoitov 
64f3694e00SDaniel Borkmann BPF_CALL_2(bpf_map_delete_elem, struct bpf_map *, map, void *, key)
65d0003ec0SAlexei Starovoitov {
66694cea39SToke Høiland-Jørgensen 	WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
67d0003ec0SAlexei Starovoitov 	return map->ops->map_delete_elem(map, key);
68d0003ec0SAlexei Starovoitov }
69d0003ec0SAlexei Starovoitov 
70a2c83fffSDaniel Borkmann const struct bpf_func_proto bpf_map_delete_elem_proto = {
71d0003ec0SAlexei Starovoitov 	.func		= bpf_map_delete_elem,
72d0003ec0SAlexei Starovoitov 	.gpl_only	= false,
7336bbef52SDaniel Borkmann 	.pkt_access	= true,
74d0003ec0SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
75d0003ec0SAlexei Starovoitov 	.arg1_type	= ARG_CONST_MAP_PTR,
76d0003ec0SAlexei Starovoitov 	.arg2_type	= ARG_PTR_TO_MAP_KEY,
77d0003ec0SAlexei Starovoitov };
7803e69b50SDaniel Borkmann 
79f1a2e44aSMauricio Vasquez B BPF_CALL_3(bpf_map_push_elem, struct bpf_map *, map, void *, value, u64, flags)
80f1a2e44aSMauricio Vasquez B {
81f1a2e44aSMauricio Vasquez B 	return map->ops->map_push_elem(map, value, flags);
82f1a2e44aSMauricio Vasquez B }
83f1a2e44aSMauricio Vasquez B 
84f1a2e44aSMauricio Vasquez B const struct bpf_func_proto bpf_map_push_elem_proto = {
85f1a2e44aSMauricio Vasquez B 	.func		= bpf_map_push_elem,
86f1a2e44aSMauricio Vasquez B 	.gpl_only	= false,
87f1a2e44aSMauricio Vasquez B 	.pkt_access	= true,
88f1a2e44aSMauricio Vasquez B 	.ret_type	= RET_INTEGER,
89f1a2e44aSMauricio Vasquez B 	.arg1_type	= ARG_CONST_MAP_PTR,
90f1a2e44aSMauricio Vasquez B 	.arg2_type	= ARG_PTR_TO_MAP_VALUE,
91f1a2e44aSMauricio Vasquez B 	.arg3_type	= ARG_ANYTHING,
92f1a2e44aSMauricio Vasquez B };
93f1a2e44aSMauricio Vasquez B 
94f1a2e44aSMauricio Vasquez B BPF_CALL_2(bpf_map_pop_elem, struct bpf_map *, map, void *, value)
95f1a2e44aSMauricio Vasquez B {
96f1a2e44aSMauricio Vasquez B 	return map->ops->map_pop_elem(map, value);
97f1a2e44aSMauricio Vasquez B }
98f1a2e44aSMauricio Vasquez B 
99f1a2e44aSMauricio Vasquez B const struct bpf_func_proto bpf_map_pop_elem_proto = {
100f1a2e44aSMauricio Vasquez B 	.func		= bpf_map_pop_elem,
101f1a2e44aSMauricio Vasquez B 	.gpl_only	= false,
102f1a2e44aSMauricio Vasquez B 	.ret_type	= RET_INTEGER,
103f1a2e44aSMauricio Vasquez B 	.arg1_type	= ARG_CONST_MAP_PTR,
104f1a2e44aSMauricio Vasquez B 	.arg2_type	= ARG_PTR_TO_UNINIT_MAP_VALUE,
105f1a2e44aSMauricio Vasquez B };
106f1a2e44aSMauricio Vasquez B 
107f1a2e44aSMauricio Vasquez B BPF_CALL_2(bpf_map_peek_elem, struct bpf_map *, map, void *, value)
108f1a2e44aSMauricio Vasquez B {
109f1a2e44aSMauricio Vasquez B 	return map->ops->map_peek_elem(map, value);
110f1a2e44aSMauricio Vasquez B }
111f1a2e44aSMauricio Vasquez B 
112f1a2e44aSMauricio Vasquez B const struct bpf_func_proto bpf_map_peek_elem_proto = {
113301a33d5SMircea Cirjaliu 	.func		= bpf_map_peek_elem,
114f1a2e44aSMauricio Vasquez B 	.gpl_only	= false,
115f1a2e44aSMauricio Vasquez B 	.ret_type	= RET_INTEGER,
116f1a2e44aSMauricio Vasquez B 	.arg1_type	= ARG_CONST_MAP_PTR,
117f1a2e44aSMauricio Vasquez B 	.arg2_type	= ARG_PTR_TO_UNINIT_MAP_VALUE,
118f1a2e44aSMauricio Vasquez B };
119f1a2e44aSMauricio Vasquez B 
12003e69b50SDaniel Borkmann const struct bpf_func_proto bpf_get_prandom_u32_proto = {
1213ad00405SDaniel Borkmann 	.func		= bpf_user_rnd_u32,
12203e69b50SDaniel Borkmann 	.gpl_only	= false,
12303e69b50SDaniel Borkmann 	.ret_type	= RET_INTEGER,
12403e69b50SDaniel Borkmann };
125c04167ceSDaniel Borkmann 
126f3694e00SDaniel Borkmann BPF_CALL_0(bpf_get_smp_processor_id)
127c04167ceSDaniel Borkmann {
12880b48c44SDaniel Borkmann 	return smp_processor_id();
129c04167ceSDaniel Borkmann }
130c04167ceSDaniel Borkmann 
131c04167ceSDaniel Borkmann const struct bpf_func_proto bpf_get_smp_processor_id_proto = {
132c04167ceSDaniel Borkmann 	.func		= bpf_get_smp_processor_id,
133c04167ceSDaniel Borkmann 	.gpl_only	= false,
134c04167ceSDaniel Borkmann 	.ret_type	= RET_INTEGER,
135c04167ceSDaniel Borkmann };
13617ca8cbfSDaniel Borkmann 
1372d0e30c3SDaniel Borkmann BPF_CALL_0(bpf_get_numa_node_id)
1382d0e30c3SDaniel Borkmann {
1392d0e30c3SDaniel Borkmann 	return numa_node_id();
1402d0e30c3SDaniel Borkmann }
1412d0e30c3SDaniel Borkmann 
1422d0e30c3SDaniel Borkmann const struct bpf_func_proto bpf_get_numa_node_id_proto = {
1432d0e30c3SDaniel Borkmann 	.func		= bpf_get_numa_node_id,
1442d0e30c3SDaniel Borkmann 	.gpl_only	= false,
1452d0e30c3SDaniel Borkmann 	.ret_type	= RET_INTEGER,
1462d0e30c3SDaniel Borkmann };
1472d0e30c3SDaniel Borkmann 
148f3694e00SDaniel Borkmann BPF_CALL_0(bpf_ktime_get_ns)
14917ca8cbfSDaniel Borkmann {
15017ca8cbfSDaniel Borkmann 	/* NMI safe access to clock monotonic */
15117ca8cbfSDaniel Borkmann 	return ktime_get_mono_fast_ns();
15217ca8cbfSDaniel Borkmann }
15317ca8cbfSDaniel Borkmann 
15417ca8cbfSDaniel Borkmann const struct bpf_func_proto bpf_ktime_get_ns_proto = {
15517ca8cbfSDaniel Borkmann 	.func		= bpf_ktime_get_ns,
156082b57e3SMaciej Żenczykowski 	.gpl_only	= false,
15717ca8cbfSDaniel Borkmann 	.ret_type	= RET_INTEGER,
15817ca8cbfSDaniel Borkmann };
159ffeedafbSAlexei Starovoitov 
16071d19214SMaciej Żenczykowski BPF_CALL_0(bpf_ktime_get_boot_ns)
16171d19214SMaciej Żenczykowski {
16271d19214SMaciej Żenczykowski 	/* NMI safe access to clock boottime */
16371d19214SMaciej Żenczykowski 	return ktime_get_boot_fast_ns();
16471d19214SMaciej Żenczykowski }
16571d19214SMaciej Żenczykowski 
16671d19214SMaciej Żenczykowski const struct bpf_func_proto bpf_ktime_get_boot_ns_proto = {
16771d19214SMaciej Żenczykowski 	.func		= bpf_ktime_get_boot_ns,
16871d19214SMaciej Żenczykowski 	.gpl_only	= false,
16971d19214SMaciej Żenczykowski 	.ret_type	= RET_INTEGER,
17071d19214SMaciej Żenczykowski };
17171d19214SMaciej Żenczykowski 
172d0551261SDmitrii Banshchikov BPF_CALL_0(bpf_ktime_get_coarse_ns)
173d0551261SDmitrii Banshchikov {
174d0551261SDmitrii Banshchikov 	return ktime_get_coarse_ns();
175d0551261SDmitrii Banshchikov }
176d0551261SDmitrii Banshchikov 
177d0551261SDmitrii Banshchikov const struct bpf_func_proto bpf_ktime_get_coarse_ns_proto = {
178d0551261SDmitrii Banshchikov 	.func		= bpf_ktime_get_coarse_ns,
179d0551261SDmitrii Banshchikov 	.gpl_only	= false,
180d0551261SDmitrii Banshchikov 	.ret_type	= RET_INTEGER,
181d0551261SDmitrii Banshchikov };
182d0551261SDmitrii Banshchikov 
183f3694e00SDaniel Borkmann BPF_CALL_0(bpf_get_current_pid_tgid)
184ffeedafbSAlexei Starovoitov {
185ffeedafbSAlexei Starovoitov 	struct task_struct *task = current;
186ffeedafbSAlexei Starovoitov 
1876088b582SDaniel Borkmann 	if (unlikely(!task))
188ffeedafbSAlexei Starovoitov 		return -EINVAL;
189ffeedafbSAlexei Starovoitov 
190ffeedafbSAlexei Starovoitov 	return (u64) task->tgid << 32 | task->pid;
191ffeedafbSAlexei Starovoitov }
192ffeedafbSAlexei Starovoitov 
193ffeedafbSAlexei Starovoitov const struct bpf_func_proto bpf_get_current_pid_tgid_proto = {
194ffeedafbSAlexei Starovoitov 	.func		= bpf_get_current_pid_tgid,
195ffeedafbSAlexei Starovoitov 	.gpl_only	= false,
196ffeedafbSAlexei Starovoitov 	.ret_type	= RET_INTEGER,
197ffeedafbSAlexei Starovoitov };
198ffeedafbSAlexei Starovoitov 
199f3694e00SDaniel Borkmann BPF_CALL_0(bpf_get_current_uid_gid)
200ffeedafbSAlexei Starovoitov {
201ffeedafbSAlexei Starovoitov 	struct task_struct *task = current;
202ffeedafbSAlexei Starovoitov 	kuid_t uid;
203ffeedafbSAlexei Starovoitov 	kgid_t gid;
204ffeedafbSAlexei Starovoitov 
2056088b582SDaniel Borkmann 	if (unlikely(!task))
206ffeedafbSAlexei Starovoitov 		return -EINVAL;
207ffeedafbSAlexei Starovoitov 
208ffeedafbSAlexei Starovoitov 	current_uid_gid(&uid, &gid);
209ffeedafbSAlexei Starovoitov 	return (u64) from_kgid(&init_user_ns, gid) << 32 |
210ffeedafbSAlexei Starovoitov 		     from_kuid(&init_user_ns, uid);
211ffeedafbSAlexei Starovoitov }
212ffeedafbSAlexei Starovoitov 
213ffeedafbSAlexei Starovoitov const struct bpf_func_proto bpf_get_current_uid_gid_proto = {
214ffeedafbSAlexei Starovoitov 	.func		= bpf_get_current_uid_gid,
215ffeedafbSAlexei Starovoitov 	.gpl_only	= false,
216ffeedafbSAlexei Starovoitov 	.ret_type	= RET_INTEGER,
217ffeedafbSAlexei Starovoitov };
218ffeedafbSAlexei Starovoitov 
219f3694e00SDaniel Borkmann BPF_CALL_2(bpf_get_current_comm, char *, buf, u32, size)
220ffeedafbSAlexei Starovoitov {
221ffeedafbSAlexei Starovoitov 	struct task_struct *task = current;
222ffeedafbSAlexei Starovoitov 
223074f528eSDaniel Borkmann 	if (unlikely(!task))
224074f528eSDaniel Borkmann 		goto err_clear;
225ffeedafbSAlexei Starovoitov 
226074f528eSDaniel Borkmann 	strncpy(buf, task->comm, size);
227074f528eSDaniel Borkmann 
228074f528eSDaniel Borkmann 	/* Verifier guarantees that size > 0. For task->comm exceeding
229074f528eSDaniel Borkmann 	 * size, guarantee that buf is %NUL-terminated. Unconditionally
230074f528eSDaniel Borkmann 	 * done here to save the size test.
231074f528eSDaniel Borkmann 	 */
232074f528eSDaniel Borkmann 	buf[size - 1] = 0;
233ffeedafbSAlexei Starovoitov 	return 0;
234074f528eSDaniel Borkmann err_clear:
235074f528eSDaniel Borkmann 	memset(buf, 0, size);
236074f528eSDaniel Borkmann 	return -EINVAL;
237ffeedafbSAlexei Starovoitov }
238ffeedafbSAlexei Starovoitov 
239ffeedafbSAlexei Starovoitov const struct bpf_func_proto bpf_get_current_comm_proto = {
240ffeedafbSAlexei Starovoitov 	.func		= bpf_get_current_comm,
241ffeedafbSAlexei Starovoitov 	.gpl_only	= false,
242ffeedafbSAlexei Starovoitov 	.ret_type	= RET_INTEGER,
24339f19ebbSAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
24439f19ebbSAlexei Starovoitov 	.arg2_type	= ARG_CONST_SIZE,
245ffeedafbSAlexei Starovoitov };
246bf6fa2c8SYonghong Song 
247d83525caSAlexei Starovoitov #if defined(CONFIG_QUEUED_SPINLOCKS) || defined(CONFIG_BPF_ARCH_SPINLOCK)
248d83525caSAlexei Starovoitov 
249d83525caSAlexei Starovoitov static inline void __bpf_spin_lock(struct bpf_spin_lock *lock)
250d83525caSAlexei Starovoitov {
251d83525caSAlexei Starovoitov 	arch_spinlock_t *l = (void *)lock;
252d83525caSAlexei Starovoitov 	union {
253d83525caSAlexei Starovoitov 		__u32 val;
254d83525caSAlexei Starovoitov 		arch_spinlock_t lock;
255d83525caSAlexei Starovoitov 	} u = { .lock = __ARCH_SPIN_LOCK_UNLOCKED };
256d83525caSAlexei Starovoitov 
257d83525caSAlexei Starovoitov 	compiletime_assert(u.val == 0, "__ARCH_SPIN_LOCK_UNLOCKED not 0");
258d83525caSAlexei Starovoitov 	BUILD_BUG_ON(sizeof(*l) != sizeof(__u32));
259d83525caSAlexei Starovoitov 	BUILD_BUG_ON(sizeof(*lock) != sizeof(__u32));
260d83525caSAlexei Starovoitov 	arch_spin_lock(l);
261d83525caSAlexei Starovoitov }
262d83525caSAlexei Starovoitov 
263d83525caSAlexei Starovoitov static inline void __bpf_spin_unlock(struct bpf_spin_lock *lock)
264d83525caSAlexei Starovoitov {
265d83525caSAlexei Starovoitov 	arch_spinlock_t *l = (void *)lock;
266d83525caSAlexei Starovoitov 
267d83525caSAlexei Starovoitov 	arch_spin_unlock(l);
268d83525caSAlexei Starovoitov }
269d83525caSAlexei Starovoitov 
270d83525caSAlexei Starovoitov #else
271d83525caSAlexei Starovoitov 
272d83525caSAlexei Starovoitov static inline void __bpf_spin_lock(struct bpf_spin_lock *lock)
273d83525caSAlexei Starovoitov {
274d83525caSAlexei Starovoitov 	atomic_t *l = (void *)lock;
275d83525caSAlexei Starovoitov 
276d83525caSAlexei Starovoitov 	BUILD_BUG_ON(sizeof(*l) != sizeof(*lock));
277d83525caSAlexei Starovoitov 	do {
278d83525caSAlexei Starovoitov 		atomic_cond_read_relaxed(l, !VAL);
279d83525caSAlexei Starovoitov 	} while (atomic_xchg(l, 1));
280d83525caSAlexei Starovoitov }
281d83525caSAlexei Starovoitov 
282d83525caSAlexei Starovoitov static inline void __bpf_spin_unlock(struct bpf_spin_lock *lock)
283d83525caSAlexei Starovoitov {
284d83525caSAlexei Starovoitov 	atomic_t *l = (void *)lock;
285d83525caSAlexei Starovoitov 
286d83525caSAlexei Starovoitov 	atomic_set_release(l, 0);
287d83525caSAlexei Starovoitov }
288d83525caSAlexei Starovoitov 
289d83525caSAlexei Starovoitov #endif
290d83525caSAlexei Starovoitov 
291d83525caSAlexei Starovoitov static DEFINE_PER_CPU(unsigned long, irqsave_flags);
292d83525caSAlexei Starovoitov 
293c1b3fed3SAlexei Starovoitov static inline void __bpf_spin_lock_irqsave(struct bpf_spin_lock *lock)
294d83525caSAlexei Starovoitov {
295d83525caSAlexei Starovoitov 	unsigned long flags;
296d83525caSAlexei Starovoitov 
297d83525caSAlexei Starovoitov 	local_irq_save(flags);
298d83525caSAlexei Starovoitov 	__bpf_spin_lock(lock);
299d83525caSAlexei Starovoitov 	__this_cpu_write(irqsave_flags, flags);
300c1b3fed3SAlexei Starovoitov }
301c1b3fed3SAlexei Starovoitov 
302c1b3fed3SAlexei Starovoitov notrace BPF_CALL_1(bpf_spin_lock, struct bpf_spin_lock *, lock)
303c1b3fed3SAlexei Starovoitov {
304c1b3fed3SAlexei Starovoitov 	__bpf_spin_lock_irqsave(lock);
305d83525caSAlexei Starovoitov 	return 0;
306d83525caSAlexei Starovoitov }
307d83525caSAlexei Starovoitov 
308d83525caSAlexei Starovoitov const struct bpf_func_proto bpf_spin_lock_proto = {
309d83525caSAlexei Starovoitov 	.func		= bpf_spin_lock,
310d83525caSAlexei Starovoitov 	.gpl_only	= false,
311d83525caSAlexei Starovoitov 	.ret_type	= RET_VOID,
312d83525caSAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_SPIN_LOCK,
313d83525caSAlexei Starovoitov };
314d83525caSAlexei Starovoitov 
315c1b3fed3SAlexei Starovoitov static inline void __bpf_spin_unlock_irqrestore(struct bpf_spin_lock *lock)
316d83525caSAlexei Starovoitov {
317d83525caSAlexei Starovoitov 	unsigned long flags;
318d83525caSAlexei Starovoitov 
319d83525caSAlexei Starovoitov 	flags = __this_cpu_read(irqsave_flags);
320d83525caSAlexei Starovoitov 	__bpf_spin_unlock(lock);
321d83525caSAlexei Starovoitov 	local_irq_restore(flags);
322c1b3fed3SAlexei Starovoitov }
323c1b3fed3SAlexei Starovoitov 
324c1b3fed3SAlexei Starovoitov notrace BPF_CALL_1(bpf_spin_unlock, struct bpf_spin_lock *, lock)
325c1b3fed3SAlexei Starovoitov {
326c1b3fed3SAlexei Starovoitov 	__bpf_spin_unlock_irqrestore(lock);
327d83525caSAlexei Starovoitov 	return 0;
328d83525caSAlexei Starovoitov }
329d83525caSAlexei Starovoitov 
330d83525caSAlexei Starovoitov const struct bpf_func_proto bpf_spin_unlock_proto = {
331d83525caSAlexei Starovoitov 	.func		= bpf_spin_unlock,
332d83525caSAlexei Starovoitov 	.gpl_only	= false,
333d83525caSAlexei Starovoitov 	.ret_type	= RET_VOID,
334d83525caSAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_SPIN_LOCK,
335d83525caSAlexei Starovoitov };
336d83525caSAlexei Starovoitov 
33796049f3aSAlexei Starovoitov void copy_map_value_locked(struct bpf_map *map, void *dst, void *src,
33896049f3aSAlexei Starovoitov 			   bool lock_src)
33996049f3aSAlexei Starovoitov {
34096049f3aSAlexei Starovoitov 	struct bpf_spin_lock *lock;
34196049f3aSAlexei Starovoitov 
34296049f3aSAlexei Starovoitov 	if (lock_src)
34396049f3aSAlexei Starovoitov 		lock = src + map->spin_lock_off;
34496049f3aSAlexei Starovoitov 	else
34596049f3aSAlexei Starovoitov 		lock = dst + map->spin_lock_off;
34696049f3aSAlexei Starovoitov 	preempt_disable();
347c1b3fed3SAlexei Starovoitov 	__bpf_spin_lock_irqsave(lock);
34896049f3aSAlexei Starovoitov 	copy_map_value(map, dst, src);
349c1b3fed3SAlexei Starovoitov 	__bpf_spin_unlock_irqrestore(lock);
35096049f3aSAlexei Starovoitov 	preempt_enable();
35196049f3aSAlexei Starovoitov }
35296049f3aSAlexei Starovoitov 
3535576b991SMartin KaFai Lau BPF_CALL_0(bpf_jiffies64)
3545576b991SMartin KaFai Lau {
3555576b991SMartin KaFai Lau 	return get_jiffies_64();
3565576b991SMartin KaFai Lau }
3575576b991SMartin KaFai Lau 
3585576b991SMartin KaFai Lau const struct bpf_func_proto bpf_jiffies64_proto = {
3595576b991SMartin KaFai Lau 	.func		= bpf_jiffies64,
3605576b991SMartin KaFai Lau 	.gpl_only	= false,
3615576b991SMartin KaFai Lau 	.ret_type	= RET_INTEGER,
3625576b991SMartin KaFai Lau };
3635576b991SMartin KaFai Lau 
364bf6fa2c8SYonghong Song #ifdef CONFIG_CGROUPS
365bf6fa2c8SYonghong Song BPF_CALL_0(bpf_get_current_cgroup_id)
366bf6fa2c8SYonghong Song {
3672d3a1e36SYonghong Song 	struct cgroup *cgrp;
3682d3a1e36SYonghong Song 	u64 cgrp_id;
369bf6fa2c8SYonghong Song 
3702d3a1e36SYonghong Song 	rcu_read_lock();
3712d3a1e36SYonghong Song 	cgrp = task_dfl_cgroup(current);
3722d3a1e36SYonghong Song 	cgrp_id = cgroup_id(cgrp);
3732d3a1e36SYonghong Song 	rcu_read_unlock();
3742d3a1e36SYonghong Song 
3752d3a1e36SYonghong Song 	return cgrp_id;
376bf6fa2c8SYonghong Song }
377bf6fa2c8SYonghong Song 
378bf6fa2c8SYonghong Song const struct bpf_func_proto bpf_get_current_cgroup_id_proto = {
379bf6fa2c8SYonghong Song 	.func		= bpf_get_current_cgroup_id,
380bf6fa2c8SYonghong Song 	.gpl_only	= false,
381bf6fa2c8SYonghong Song 	.ret_type	= RET_INTEGER,
382bf6fa2c8SYonghong Song };
383cd339431SRoman Gushchin 
3840f09abd1SDaniel Borkmann BPF_CALL_1(bpf_get_current_ancestor_cgroup_id, int, ancestor_level)
3850f09abd1SDaniel Borkmann {
3862d3a1e36SYonghong Song 	struct cgroup *cgrp;
3870f09abd1SDaniel Borkmann 	struct cgroup *ancestor;
3882d3a1e36SYonghong Song 	u64 cgrp_id;
3890f09abd1SDaniel Borkmann 
3902d3a1e36SYonghong Song 	rcu_read_lock();
3912d3a1e36SYonghong Song 	cgrp = task_dfl_cgroup(current);
3920f09abd1SDaniel Borkmann 	ancestor = cgroup_ancestor(cgrp, ancestor_level);
3932d3a1e36SYonghong Song 	cgrp_id = ancestor ? cgroup_id(ancestor) : 0;
3942d3a1e36SYonghong Song 	rcu_read_unlock();
3952d3a1e36SYonghong Song 
3962d3a1e36SYonghong Song 	return cgrp_id;
3970f09abd1SDaniel Borkmann }
3980f09abd1SDaniel Borkmann 
3990f09abd1SDaniel Borkmann const struct bpf_func_proto bpf_get_current_ancestor_cgroup_id_proto = {
4000f09abd1SDaniel Borkmann 	.func		= bpf_get_current_ancestor_cgroup_id,
4010f09abd1SDaniel Borkmann 	.gpl_only	= false,
4020f09abd1SDaniel Borkmann 	.ret_type	= RET_INTEGER,
4030f09abd1SDaniel Borkmann 	.arg1_type	= ARG_ANYTHING,
4040f09abd1SDaniel Borkmann };
4050f09abd1SDaniel Borkmann 
4068bad74f9SRoman Gushchin #ifdef CONFIG_CGROUP_BPF
407cd339431SRoman Gushchin 
408cd339431SRoman Gushchin BPF_CALL_2(bpf_get_local_storage, struct bpf_map *, map, u64, flags)
409cd339431SRoman Gushchin {
4108bad74f9SRoman Gushchin 	/* flags argument is not used now,
4118bad74f9SRoman Gushchin 	 * but provides an ability to extend the API.
4128bad74f9SRoman Gushchin 	 * verifier checks that its value is correct.
413cd339431SRoman Gushchin 	 */
4148bad74f9SRoman Gushchin 	enum bpf_cgroup_storage_type stype = cgroup_storage_type(map);
415c7603cfaSAndrii Nakryiko 	struct bpf_cgroup_storage *storage;
416c7603cfaSAndrii Nakryiko 	struct bpf_cg_run_ctx *ctx;
417b741f163SRoman Gushchin 	void *ptr;
4188bad74f9SRoman Gushchin 
419c7603cfaSAndrii Nakryiko 	/* get current cgroup storage from BPF run context */
420c7603cfaSAndrii Nakryiko 	ctx = container_of(current->bpf_ctx, struct bpf_cg_run_ctx, run_ctx);
421c7603cfaSAndrii Nakryiko 	storage = ctx->prog_item->cgroup_storage[stype];
422f294b37eSRoman Gushchin 
423b741f163SRoman Gushchin 	if (stype == BPF_CGROUP_STORAGE_SHARED)
424b741f163SRoman Gushchin 		ptr = &READ_ONCE(storage->buf)->data[0];
425b741f163SRoman Gushchin 	else
426b741f163SRoman Gushchin 		ptr = this_cpu_ptr(storage->percpu_buf);
427b741f163SRoman Gushchin 
428b741f163SRoman Gushchin 	return (unsigned long)ptr;
429cd339431SRoman Gushchin }
430cd339431SRoman Gushchin 
431cd339431SRoman Gushchin const struct bpf_func_proto bpf_get_local_storage_proto = {
432cd339431SRoman Gushchin 	.func		= bpf_get_local_storage,
433cd339431SRoman Gushchin 	.gpl_only	= false,
434cd339431SRoman Gushchin 	.ret_type	= RET_PTR_TO_MAP_VALUE,
435cd339431SRoman Gushchin 	.arg1_type	= ARG_CONST_MAP_PTR,
436cd339431SRoman Gushchin 	.arg2_type	= ARG_ANYTHING,
437cd339431SRoman Gushchin };
438bf6fa2c8SYonghong Song #endif
439d7a4cb9bSAndrey Ignatov 
440d7a4cb9bSAndrey Ignatov #define BPF_STRTOX_BASE_MASK 0x1F
441d7a4cb9bSAndrey Ignatov 
442d7a4cb9bSAndrey Ignatov static int __bpf_strtoull(const char *buf, size_t buf_len, u64 flags,
443d7a4cb9bSAndrey Ignatov 			  unsigned long long *res, bool *is_negative)
444d7a4cb9bSAndrey Ignatov {
445d7a4cb9bSAndrey Ignatov 	unsigned int base = flags & BPF_STRTOX_BASE_MASK;
446d7a4cb9bSAndrey Ignatov 	const char *cur_buf = buf;
447d7a4cb9bSAndrey Ignatov 	size_t cur_len = buf_len;
448d7a4cb9bSAndrey Ignatov 	unsigned int consumed;
449d7a4cb9bSAndrey Ignatov 	size_t val_len;
450d7a4cb9bSAndrey Ignatov 	char str[64];
451d7a4cb9bSAndrey Ignatov 
452d7a4cb9bSAndrey Ignatov 	if (!buf || !buf_len || !res || !is_negative)
453d7a4cb9bSAndrey Ignatov 		return -EINVAL;
454d7a4cb9bSAndrey Ignatov 
455d7a4cb9bSAndrey Ignatov 	if (base != 0 && base != 8 && base != 10 && base != 16)
456d7a4cb9bSAndrey Ignatov 		return -EINVAL;
457d7a4cb9bSAndrey Ignatov 
458d7a4cb9bSAndrey Ignatov 	if (flags & ~BPF_STRTOX_BASE_MASK)
459d7a4cb9bSAndrey Ignatov 		return -EINVAL;
460d7a4cb9bSAndrey Ignatov 
461d7a4cb9bSAndrey Ignatov 	while (cur_buf < buf + buf_len && isspace(*cur_buf))
462d7a4cb9bSAndrey Ignatov 		++cur_buf;
463d7a4cb9bSAndrey Ignatov 
464d7a4cb9bSAndrey Ignatov 	*is_negative = (cur_buf < buf + buf_len && *cur_buf == '-');
465d7a4cb9bSAndrey Ignatov 	if (*is_negative)
466d7a4cb9bSAndrey Ignatov 		++cur_buf;
467d7a4cb9bSAndrey Ignatov 
468d7a4cb9bSAndrey Ignatov 	consumed = cur_buf - buf;
469d7a4cb9bSAndrey Ignatov 	cur_len -= consumed;
470d7a4cb9bSAndrey Ignatov 	if (!cur_len)
471d7a4cb9bSAndrey Ignatov 		return -EINVAL;
472d7a4cb9bSAndrey Ignatov 
473d7a4cb9bSAndrey Ignatov 	cur_len = min(cur_len, sizeof(str) - 1);
474d7a4cb9bSAndrey Ignatov 	memcpy(str, cur_buf, cur_len);
475d7a4cb9bSAndrey Ignatov 	str[cur_len] = '\0';
476d7a4cb9bSAndrey Ignatov 	cur_buf = str;
477d7a4cb9bSAndrey Ignatov 
478d7a4cb9bSAndrey Ignatov 	cur_buf = _parse_integer_fixup_radix(cur_buf, &base);
479d7a4cb9bSAndrey Ignatov 	val_len = _parse_integer(cur_buf, base, res);
480d7a4cb9bSAndrey Ignatov 
481d7a4cb9bSAndrey Ignatov 	if (val_len & KSTRTOX_OVERFLOW)
482d7a4cb9bSAndrey Ignatov 		return -ERANGE;
483d7a4cb9bSAndrey Ignatov 
484d7a4cb9bSAndrey Ignatov 	if (val_len == 0)
485d7a4cb9bSAndrey Ignatov 		return -EINVAL;
486d7a4cb9bSAndrey Ignatov 
487d7a4cb9bSAndrey Ignatov 	cur_buf += val_len;
488d7a4cb9bSAndrey Ignatov 	consumed += cur_buf - str;
489d7a4cb9bSAndrey Ignatov 
490d7a4cb9bSAndrey Ignatov 	return consumed;
491d7a4cb9bSAndrey Ignatov }
492d7a4cb9bSAndrey Ignatov 
493d7a4cb9bSAndrey Ignatov static int __bpf_strtoll(const char *buf, size_t buf_len, u64 flags,
494d7a4cb9bSAndrey Ignatov 			 long long *res)
495d7a4cb9bSAndrey Ignatov {
496d7a4cb9bSAndrey Ignatov 	unsigned long long _res;
497d7a4cb9bSAndrey Ignatov 	bool is_negative;
498d7a4cb9bSAndrey Ignatov 	int err;
499d7a4cb9bSAndrey Ignatov 
500d7a4cb9bSAndrey Ignatov 	err = __bpf_strtoull(buf, buf_len, flags, &_res, &is_negative);
501d7a4cb9bSAndrey Ignatov 	if (err < 0)
502d7a4cb9bSAndrey Ignatov 		return err;
503d7a4cb9bSAndrey Ignatov 	if (is_negative) {
504d7a4cb9bSAndrey Ignatov 		if ((long long)-_res > 0)
505d7a4cb9bSAndrey Ignatov 			return -ERANGE;
506d7a4cb9bSAndrey Ignatov 		*res = -_res;
507d7a4cb9bSAndrey Ignatov 	} else {
508d7a4cb9bSAndrey Ignatov 		if ((long long)_res < 0)
509d7a4cb9bSAndrey Ignatov 			return -ERANGE;
510d7a4cb9bSAndrey Ignatov 		*res = _res;
511d7a4cb9bSAndrey Ignatov 	}
512d7a4cb9bSAndrey Ignatov 	return err;
513d7a4cb9bSAndrey Ignatov }
514d7a4cb9bSAndrey Ignatov 
515d7a4cb9bSAndrey Ignatov BPF_CALL_4(bpf_strtol, const char *, buf, size_t, buf_len, u64, flags,
516d7a4cb9bSAndrey Ignatov 	   long *, res)
517d7a4cb9bSAndrey Ignatov {
518d7a4cb9bSAndrey Ignatov 	long long _res;
519d7a4cb9bSAndrey Ignatov 	int err;
520d7a4cb9bSAndrey Ignatov 
521d7a4cb9bSAndrey Ignatov 	err = __bpf_strtoll(buf, buf_len, flags, &_res);
522d7a4cb9bSAndrey Ignatov 	if (err < 0)
523d7a4cb9bSAndrey Ignatov 		return err;
524d7a4cb9bSAndrey Ignatov 	if (_res != (long)_res)
525d7a4cb9bSAndrey Ignatov 		return -ERANGE;
526d7a4cb9bSAndrey Ignatov 	*res = _res;
527d7a4cb9bSAndrey Ignatov 	return err;
528d7a4cb9bSAndrey Ignatov }
529d7a4cb9bSAndrey Ignatov 
530d7a4cb9bSAndrey Ignatov const struct bpf_func_proto bpf_strtol_proto = {
531d7a4cb9bSAndrey Ignatov 	.func		= bpf_strtol,
532d7a4cb9bSAndrey Ignatov 	.gpl_only	= false,
533d7a4cb9bSAndrey Ignatov 	.ret_type	= RET_INTEGER,
534d7a4cb9bSAndrey Ignatov 	.arg1_type	= ARG_PTR_TO_MEM,
535d7a4cb9bSAndrey Ignatov 	.arg2_type	= ARG_CONST_SIZE,
536d7a4cb9bSAndrey Ignatov 	.arg3_type	= ARG_ANYTHING,
537d7a4cb9bSAndrey Ignatov 	.arg4_type	= ARG_PTR_TO_LONG,
538d7a4cb9bSAndrey Ignatov };
539d7a4cb9bSAndrey Ignatov 
540d7a4cb9bSAndrey Ignatov BPF_CALL_4(bpf_strtoul, const char *, buf, size_t, buf_len, u64, flags,
541d7a4cb9bSAndrey Ignatov 	   unsigned long *, res)
542d7a4cb9bSAndrey Ignatov {
543d7a4cb9bSAndrey Ignatov 	unsigned long long _res;
544d7a4cb9bSAndrey Ignatov 	bool is_negative;
545d7a4cb9bSAndrey Ignatov 	int err;
546d7a4cb9bSAndrey Ignatov 
547d7a4cb9bSAndrey Ignatov 	err = __bpf_strtoull(buf, buf_len, flags, &_res, &is_negative);
548d7a4cb9bSAndrey Ignatov 	if (err < 0)
549d7a4cb9bSAndrey Ignatov 		return err;
550d7a4cb9bSAndrey Ignatov 	if (is_negative)
551d7a4cb9bSAndrey Ignatov 		return -EINVAL;
552d7a4cb9bSAndrey Ignatov 	if (_res != (unsigned long)_res)
553d7a4cb9bSAndrey Ignatov 		return -ERANGE;
554d7a4cb9bSAndrey Ignatov 	*res = _res;
555d7a4cb9bSAndrey Ignatov 	return err;
556d7a4cb9bSAndrey Ignatov }
557d7a4cb9bSAndrey Ignatov 
558d7a4cb9bSAndrey Ignatov const struct bpf_func_proto bpf_strtoul_proto = {
559d7a4cb9bSAndrey Ignatov 	.func		= bpf_strtoul,
560d7a4cb9bSAndrey Ignatov 	.gpl_only	= false,
561d7a4cb9bSAndrey Ignatov 	.ret_type	= RET_INTEGER,
562d7a4cb9bSAndrey Ignatov 	.arg1_type	= ARG_PTR_TO_MEM,
563d7a4cb9bSAndrey Ignatov 	.arg2_type	= ARG_CONST_SIZE,
564d7a4cb9bSAndrey Ignatov 	.arg3_type	= ARG_ANYTHING,
565d7a4cb9bSAndrey Ignatov 	.arg4_type	= ARG_PTR_TO_LONG,
566d7a4cb9bSAndrey Ignatov };
5678bad74f9SRoman Gushchin #endif
568b4490c5cSCarlos Neira 
569c5fb1993SHou Tao BPF_CALL_3(bpf_strncmp, const char *, s1, u32, s1_sz, const char *, s2)
570c5fb1993SHou Tao {
571c5fb1993SHou Tao 	return strncmp(s1, s2, s1_sz);
572c5fb1993SHou Tao }
573c5fb1993SHou Tao 
574c5fb1993SHou Tao const struct bpf_func_proto bpf_strncmp_proto = {
575c5fb1993SHou Tao 	.func		= bpf_strncmp,
576c5fb1993SHou Tao 	.gpl_only	= false,
577c5fb1993SHou Tao 	.ret_type	= RET_INTEGER,
578c5fb1993SHou Tao 	.arg1_type	= ARG_PTR_TO_MEM,
579c5fb1993SHou Tao 	.arg2_type	= ARG_CONST_SIZE,
580c5fb1993SHou Tao 	.arg3_type	= ARG_PTR_TO_CONST_STR,
581c5fb1993SHou Tao };
582c5fb1993SHou Tao 
583b4490c5cSCarlos Neira BPF_CALL_4(bpf_get_ns_current_pid_tgid, u64, dev, u64, ino,
584b4490c5cSCarlos Neira 	   struct bpf_pidns_info *, nsdata, u32, size)
585b4490c5cSCarlos Neira {
586b4490c5cSCarlos Neira 	struct task_struct *task = current;
587b4490c5cSCarlos Neira 	struct pid_namespace *pidns;
588b4490c5cSCarlos Neira 	int err = -EINVAL;
589b4490c5cSCarlos Neira 
590b4490c5cSCarlos Neira 	if (unlikely(size != sizeof(struct bpf_pidns_info)))
591b4490c5cSCarlos Neira 		goto clear;
592b4490c5cSCarlos Neira 
593b4490c5cSCarlos Neira 	if (unlikely((u64)(dev_t)dev != dev))
594b4490c5cSCarlos Neira 		goto clear;
595b4490c5cSCarlos Neira 
596b4490c5cSCarlos Neira 	if (unlikely(!task))
597b4490c5cSCarlos Neira 		goto clear;
598b4490c5cSCarlos Neira 
599b4490c5cSCarlos Neira 	pidns = task_active_pid_ns(task);
600b4490c5cSCarlos Neira 	if (unlikely(!pidns)) {
601b4490c5cSCarlos Neira 		err = -ENOENT;
602b4490c5cSCarlos Neira 		goto clear;
603b4490c5cSCarlos Neira 	}
604b4490c5cSCarlos Neira 
605b4490c5cSCarlos Neira 	if (!ns_match(&pidns->ns, (dev_t)dev, ino))
606b4490c5cSCarlos Neira 		goto clear;
607b4490c5cSCarlos Neira 
608b4490c5cSCarlos Neira 	nsdata->pid = task_pid_nr_ns(task, pidns);
609b4490c5cSCarlos Neira 	nsdata->tgid = task_tgid_nr_ns(task, pidns);
610b4490c5cSCarlos Neira 	return 0;
611b4490c5cSCarlos Neira clear:
612b4490c5cSCarlos Neira 	memset((void *)nsdata, 0, (size_t) size);
613b4490c5cSCarlos Neira 	return err;
614b4490c5cSCarlos Neira }
615b4490c5cSCarlos Neira 
616b4490c5cSCarlos Neira const struct bpf_func_proto bpf_get_ns_current_pid_tgid_proto = {
617b4490c5cSCarlos Neira 	.func		= bpf_get_ns_current_pid_tgid,
618b4490c5cSCarlos Neira 	.gpl_only	= false,
619b4490c5cSCarlos Neira 	.ret_type	= RET_INTEGER,
620b4490c5cSCarlos Neira 	.arg1_type	= ARG_ANYTHING,
621b4490c5cSCarlos Neira 	.arg2_type	= ARG_ANYTHING,
622b4490c5cSCarlos Neira 	.arg3_type      = ARG_PTR_TO_UNINIT_MEM,
623b4490c5cSCarlos Neira 	.arg4_type      = ARG_CONST_SIZE,
624b4490c5cSCarlos Neira };
6256890896bSStanislav Fomichev 
6266890896bSStanislav Fomichev static const struct bpf_func_proto bpf_get_raw_smp_processor_id_proto = {
6276890896bSStanislav Fomichev 	.func		= bpf_get_raw_cpu_id,
6286890896bSStanislav Fomichev 	.gpl_only	= false,
6296890896bSStanislav Fomichev 	.ret_type	= RET_INTEGER,
6306890896bSStanislav Fomichev };
6316890896bSStanislav Fomichev 
6326890896bSStanislav Fomichev BPF_CALL_5(bpf_event_output_data, void *, ctx, struct bpf_map *, map,
6336890896bSStanislav Fomichev 	   u64, flags, void *, data, u64, size)
6346890896bSStanislav Fomichev {
6356890896bSStanislav Fomichev 	if (unlikely(flags & ~(BPF_F_INDEX_MASK)))
6366890896bSStanislav Fomichev 		return -EINVAL;
6376890896bSStanislav Fomichev 
6386890896bSStanislav Fomichev 	return bpf_event_output(map, flags, data, size, NULL, 0, NULL);
6396890896bSStanislav Fomichev }
6406890896bSStanislav Fomichev 
6416890896bSStanislav Fomichev const struct bpf_func_proto bpf_event_output_data_proto =  {
6426890896bSStanislav Fomichev 	.func		= bpf_event_output_data,
6436890896bSStanislav Fomichev 	.gpl_only       = true,
6446890896bSStanislav Fomichev 	.ret_type       = RET_INTEGER,
6456890896bSStanislav Fomichev 	.arg1_type      = ARG_PTR_TO_CTX,
6466890896bSStanislav Fomichev 	.arg2_type      = ARG_CONST_MAP_PTR,
6476890896bSStanislav Fomichev 	.arg3_type      = ARG_ANYTHING,
6486890896bSStanislav Fomichev 	.arg4_type      = ARG_PTR_TO_MEM,
6496890896bSStanislav Fomichev 	.arg5_type      = ARG_CONST_SIZE_OR_ZERO,
6506890896bSStanislav Fomichev };
6516890896bSStanislav Fomichev 
65207be4c4aSAlexei Starovoitov BPF_CALL_3(bpf_copy_from_user, void *, dst, u32, size,
65307be4c4aSAlexei Starovoitov 	   const void __user *, user_ptr)
65407be4c4aSAlexei Starovoitov {
65507be4c4aSAlexei Starovoitov 	int ret = copy_from_user(dst, user_ptr, size);
65607be4c4aSAlexei Starovoitov 
65707be4c4aSAlexei Starovoitov 	if (unlikely(ret)) {
65807be4c4aSAlexei Starovoitov 		memset(dst, 0, size);
65907be4c4aSAlexei Starovoitov 		ret = -EFAULT;
66007be4c4aSAlexei Starovoitov 	}
66107be4c4aSAlexei Starovoitov 
66207be4c4aSAlexei Starovoitov 	return ret;
66307be4c4aSAlexei Starovoitov }
66407be4c4aSAlexei Starovoitov 
66507be4c4aSAlexei Starovoitov const struct bpf_func_proto bpf_copy_from_user_proto = {
66607be4c4aSAlexei Starovoitov 	.func		= bpf_copy_from_user,
66707be4c4aSAlexei Starovoitov 	.gpl_only	= false,
66807be4c4aSAlexei Starovoitov 	.ret_type	= RET_INTEGER,
66907be4c4aSAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_UNINIT_MEM,
67007be4c4aSAlexei Starovoitov 	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
67107be4c4aSAlexei Starovoitov 	.arg3_type	= ARG_ANYTHING,
67207be4c4aSAlexei Starovoitov };
67307be4c4aSAlexei Starovoitov 
674eaa6bcb7SHao Luo BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu)
675eaa6bcb7SHao Luo {
676eaa6bcb7SHao Luo 	if (cpu >= nr_cpu_ids)
677eaa6bcb7SHao Luo 		return (unsigned long)NULL;
678eaa6bcb7SHao Luo 
679eaa6bcb7SHao Luo 	return (unsigned long)per_cpu_ptr((const void __percpu *)ptr, cpu);
680eaa6bcb7SHao Luo }
681eaa6bcb7SHao Luo 
682eaa6bcb7SHao Luo const struct bpf_func_proto bpf_per_cpu_ptr_proto = {
683eaa6bcb7SHao Luo 	.func		= bpf_per_cpu_ptr,
684eaa6bcb7SHao Luo 	.gpl_only	= false,
685*34d3a78cSHao Luo 	.ret_type	= RET_PTR_TO_MEM_OR_BTF_ID | PTR_MAYBE_NULL | MEM_RDONLY,
686eaa6bcb7SHao Luo 	.arg1_type	= ARG_PTR_TO_PERCPU_BTF_ID,
687eaa6bcb7SHao Luo 	.arg2_type	= ARG_ANYTHING,
688eaa6bcb7SHao Luo };
689eaa6bcb7SHao Luo 
69063d9b80dSHao Luo BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr)
69163d9b80dSHao Luo {
69263d9b80dSHao Luo 	return (unsigned long)this_cpu_ptr((const void __percpu *)percpu_ptr);
69363d9b80dSHao Luo }
69463d9b80dSHao Luo 
69563d9b80dSHao Luo const struct bpf_func_proto bpf_this_cpu_ptr_proto = {
69663d9b80dSHao Luo 	.func		= bpf_this_cpu_ptr,
69763d9b80dSHao Luo 	.gpl_only	= false,
698*34d3a78cSHao Luo 	.ret_type	= RET_PTR_TO_MEM_OR_BTF_ID | MEM_RDONLY,
69963d9b80dSHao Luo 	.arg1_type	= ARG_PTR_TO_PERCPU_BTF_ID,
70063d9b80dSHao Luo };
70163d9b80dSHao Luo 
702d9c9e4dbSFlorent Revest static int bpf_trace_copy_string(char *buf, void *unsafe_ptr, char fmt_ptype,
703d9c9e4dbSFlorent Revest 		size_t bufsz)
704d9c9e4dbSFlorent Revest {
705d9c9e4dbSFlorent Revest 	void __user *user_ptr = (__force void __user *)unsafe_ptr;
706d9c9e4dbSFlorent Revest 
707d9c9e4dbSFlorent Revest 	buf[0] = 0;
708d9c9e4dbSFlorent Revest 
709d9c9e4dbSFlorent Revest 	switch (fmt_ptype) {
710d9c9e4dbSFlorent Revest 	case 's':
711d9c9e4dbSFlorent Revest #ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
712d9c9e4dbSFlorent Revest 		if ((unsigned long)unsafe_ptr < TASK_SIZE)
713d9c9e4dbSFlorent Revest 			return strncpy_from_user_nofault(buf, user_ptr, bufsz);
714d9c9e4dbSFlorent Revest 		fallthrough;
715d9c9e4dbSFlorent Revest #endif
716d9c9e4dbSFlorent Revest 	case 'k':
717d9c9e4dbSFlorent Revest 		return strncpy_from_kernel_nofault(buf, unsafe_ptr, bufsz);
718d9c9e4dbSFlorent Revest 	case 'u':
719d9c9e4dbSFlorent Revest 		return strncpy_from_user_nofault(buf, user_ptr, bufsz);
720d9c9e4dbSFlorent Revest 	}
721d9c9e4dbSFlorent Revest 
722d9c9e4dbSFlorent Revest 	return -EINVAL;
723d9c9e4dbSFlorent Revest }
724d9c9e4dbSFlorent Revest 
7258afcc19fSFlorent Revest /* Per-cpu temp buffers used by printf-like helpers to store the bprintf binary
7268afcc19fSFlorent Revest  * arguments representation.
727d9c9e4dbSFlorent Revest  */
7288afcc19fSFlorent Revest #define MAX_BPRINTF_BUF_LEN	512
729d9c9e4dbSFlorent Revest 
730e2d5b2bbSFlorent Revest /* Support executing three nested bprintf helper calls on a given CPU */
7310af02eb2SFlorent Revest #define MAX_BPRINTF_NEST_LEVEL	3
732e2d5b2bbSFlorent Revest struct bpf_bprintf_buffers {
7330af02eb2SFlorent Revest 	char tmp_bufs[MAX_BPRINTF_NEST_LEVEL][MAX_BPRINTF_BUF_LEN];
734d9c9e4dbSFlorent Revest };
735e2d5b2bbSFlorent Revest static DEFINE_PER_CPU(struct bpf_bprintf_buffers, bpf_bprintf_bufs);
736e2d5b2bbSFlorent Revest static DEFINE_PER_CPU(int, bpf_bprintf_nest_level);
737d9c9e4dbSFlorent Revest 
738d9c9e4dbSFlorent Revest static int try_get_fmt_tmp_buf(char **tmp_buf)
739d9c9e4dbSFlorent Revest {
740e2d5b2bbSFlorent Revest 	struct bpf_bprintf_buffers *bufs;
741e2d5b2bbSFlorent Revest 	int nest_level;
742d9c9e4dbSFlorent Revest 
743d9c9e4dbSFlorent Revest 	preempt_disable();
744e2d5b2bbSFlorent Revest 	nest_level = this_cpu_inc_return(bpf_bprintf_nest_level);
7450af02eb2SFlorent Revest 	if (WARN_ON_ONCE(nest_level > MAX_BPRINTF_NEST_LEVEL)) {
746e2d5b2bbSFlorent Revest 		this_cpu_dec(bpf_bprintf_nest_level);
747d9c9e4dbSFlorent Revest 		preempt_enable();
748d9c9e4dbSFlorent Revest 		return -EBUSY;
749d9c9e4dbSFlorent Revest 	}
750e2d5b2bbSFlorent Revest 	bufs = this_cpu_ptr(&bpf_bprintf_bufs);
751e2d5b2bbSFlorent Revest 	*tmp_buf = bufs->tmp_bufs[nest_level - 1];
752d9c9e4dbSFlorent Revest 
753d9c9e4dbSFlorent Revest 	return 0;
754d9c9e4dbSFlorent Revest }
755d9c9e4dbSFlorent Revest 
75648cac3f4SFlorent Revest void bpf_bprintf_cleanup(void)
757d9c9e4dbSFlorent Revest {
758e2d5b2bbSFlorent Revest 	if (this_cpu_read(bpf_bprintf_nest_level)) {
759e2d5b2bbSFlorent Revest 		this_cpu_dec(bpf_bprintf_nest_level);
760d9c9e4dbSFlorent Revest 		preempt_enable();
761d9c9e4dbSFlorent Revest 	}
762d9c9e4dbSFlorent Revest }
763d9c9e4dbSFlorent Revest 
764d9c9e4dbSFlorent Revest /*
76548cac3f4SFlorent Revest  * bpf_bprintf_prepare - Generic pass on format strings for bprintf-like helpers
766d9c9e4dbSFlorent Revest  *
767d9c9e4dbSFlorent Revest  * Returns a negative value if fmt is an invalid format string or 0 otherwise.
768d9c9e4dbSFlorent Revest  *
769d9c9e4dbSFlorent Revest  * This can be used in two ways:
77048cac3f4SFlorent Revest  * - Format string verification only: when bin_args is NULL
771d9c9e4dbSFlorent Revest  * - Arguments preparation: in addition to the above verification, it writes in
77248cac3f4SFlorent Revest  *   bin_args a binary representation of arguments usable by bstr_printf where
77348cac3f4SFlorent Revest  *   pointers from BPF have been sanitized.
774d9c9e4dbSFlorent Revest  *
775d9c9e4dbSFlorent Revest  * In argument preparation mode, if 0 is returned, safe temporary buffers are
77648cac3f4SFlorent Revest  * allocated and bpf_bprintf_cleanup should be called to free them after use.
777d9c9e4dbSFlorent Revest  */
77848cac3f4SFlorent Revest int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args,
77948cac3f4SFlorent Revest 			u32 **bin_args, u32 num_args)
780d9c9e4dbSFlorent Revest {
78148cac3f4SFlorent Revest 	char *unsafe_ptr = NULL, *tmp_buf = NULL, *tmp_buf_end, *fmt_end;
78248cac3f4SFlorent Revest 	size_t sizeof_cur_arg, sizeof_cur_ip;
78348cac3f4SFlorent Revest 	int err, i, num_spec = 0;
784d9c9e4dbSFlorent Revest 	u64 cur_arg;
78548cac3f4SFlorent Revest 	char fmt_ptype, cur_ip[16], ip_spec[] = "%pXX";
786d9c9e4dbSFlorent Revest 
787d9c9e4dbSFlorent Revest 	fmt_end = strnchr(fmt, fmt_size, 0);
788d9c9e4dbSFlorent Revest 	if (!fmt_end)
789d9c9e4dbSFlorent Revest 		return -EINVAL;
790d9c9e4dbSFlorent Revest 	fmt_size = fmt_end - fmt;
791d9c9e4dbSFlorent Revest 
79248cac3f4SFlorent Revest 	if (bin_args) {
79348cac3f4SFlorent Revest 		if (num_args && try_get_fmt_tmp_buf(&tmp_buf))
79448cac3f4SFlorent Revest 			return -EBUSY;
79548cac3f4SFlorent Revest 
7968afcc19fSFlorent Revest 		tmp_buf_end = tmp_buf + MAX_BPRINTF_BUF_LEN;
79748cac3f4SFlorent Revest 		*bin_args = (u32 *)tmp_buf;
79848cac3f4SFlorent Revest 	}
79948cac3f4SFlorent Revest 
800d9c9e4dbSFlorent Revest 	for (i = 0; i < fmt_size; i++) {
801d9c9e4dbSFlorent Revest 		if ((!isprint(fmt[i]) && !isspace(fmt[i])) || !isascii(fmt[i])) {
802d9c9e4dbSFlorent Revest 			err = -EINVAL;
80348cac3f4SFlorent Revest 			goto out;
804d9c9e4dbSFlorent Revest 		}
805d9c9e4dbSFlorent Revest 
806d9c9e4dbSFlorent Revest 		if (fmt[i] != '%')
807d9c9e4dbSFlorent Revest 			continue;
808d9c9e4dbSFlorent Revest 
809d9c9e4dbSFlorent Revest 		if (fmt[i + 1] == '%') {
810d9c9e4dbSFlorent Revest 			i++;
811d9c9e4dbSFlorent Revest 			continue;
812d9c9e4dbSFlorent Revest 		}
813d9c9e4dbSFlorent Revest 
814d9c9e4dbSFlorent Revest 		if (num_spec >= num_args) {
815d9c9e4dbSFlorent Revest 			err = -EINVAL;
81648cac3f4SFlorent Revest 			goto out;
817d9c9e4dbSFlorent Revest 		}
818d9c9e4dbSFlorent Revest 
819d9c9e4dbSFlorent Revest 		/* The string is zero-terminated so if fmt[i] != 0, we can
820d9c9e4dbSFlorent Revest 		 * always access fmt[i + 1], in the worst case it will be a 0
821d9c9e4dbSFlorent Revest 		 */
822d9c9e4dbSFlorent Revest 		i++;
823d9c9e4dbSFlorent Revest 
824d9c9e4dbSFlorent Revest 		/* skip optional "[0 +-][num]" width formatting field */
825d9c9e4dbSFlorent Revest 		while (fmt[i] == '0' || fmt[i] == '+'  || fmt[i] == '-' ||
826d9c9e4dbSFlorent Revest 		       fmt[i] == ' ')
827d9c9e4dbSFlorent Revest 			i++;
828d9c9e4dbSFlorent Revest 		if (fmt[i] >= '1' && fmt[i] <= '9') {
829d9c9e4dbSFlorent Revest 			i++;
830d9c9e4dbSFlorent Revest 			while (fmt[i] >= '0' && fmt[i] <= '9')
831d9c9e4dbSFlorent Revest 				i++;
832d9c9e4dbSFlorent Revest 		}
833d9c9e4dbSFlorent Revest 
834d9c9e4dbSFlorent Revest 		if (fmt[i] == 'p') {
83548cac3f4SFlorent Revest 			sizeof_cur_arg = sizeof(long);
836d9c9e4dbSFlorent Revest 
837d9c9e4dbSFlorent Revest 			if ((fmt[i + 1] == 'k' || fmt[i + 1] == 'u') &&
838d9c9e4dbSFlorent Revest 			    fmt[i + 2] == 's') {
839d9c9e4dbSFlorent Revest 				fmt_ptype = fmt[i + 1];
840d9c9e4dbSFlorent Revest 				i += 2;
841d9c9e4dbSFlorent Revest 				goto fmt_str;
842d9c9e4dbSFlorent Revest 			}
843d9c9e4dbSFlorent Revest 
844d9c9e4dbSFlorent Revest 			if (fmt[i + 1] == 0 || isspace(fmt[i + 1]) ||
845d9c9e4dbSFlorent Revest 			    ispunct(fmt[i + 1]) || fmt[i + 1] == 'K' ||
84648cac3f4SFlorent Revest 			    fmt[i + 1] == 'x' || fmt[i + 1] == 's' ||
84748cac3f4SFlorent Revest 			    fmt[i + 1] == 'S') {
848d9c9e4dbSFlorent Revest 				/* just kernel pointers */
84948cac3f4SFlorent Revest 				if (tmp_buf)
850d9c9e4dbSFlorent Revest 					cur_arg = raw_args[num_spec];
85148cac3f4SFlorent Revest 				i++;
85248cac3f4SFlorent Revest 				goto nocopy_fmt;
85348cac3f4SFlorent Revest 			}
85448cac3f4SFlorent Revest 
85548cac3f4SFlorent Revest 			if (fmt[i + 1] == 'B') {
85648cac3f4SFlorent Revest 				if (tmp_buf)  {
85748cac3f4SFlorent Revest 					err = snprintf(tmp_buf,
85848cac3f4SFlorent Revest 						       (tmp_buf_end - tmp_buf),
85948cac3f4SFlorent Revest 						       "%pB",
86048cac3f4SFlorent Revest 						       (void *)(long)raw_args[num_spec]);
86148cac3f4SFlorent Revest 					tmp_buf += (err + 1);
86248cac3f4SFlorent Revest 				}
86348cac3f4SFlorent Revest 
86448cac3f4SFlorent Revest 				i++;
86548cac3f4SFlorent Revest 				num_spec++;
86648cac3f4SFlorent Revest 				continue;
867d9c9e4dbSFlorent Revest 			}
868d9c9e4dbSFlorent Revest 
869d9c9e4dbSFlorent Revest 			/* only support "%pI4", "%pi4", "%pI6" and "%pi6". */
870d9c9e4dbSFlorent Revest 			if ((fmt[i + 1] != 'i' && fmt[i + 1] != 'I') ||
871d9c9e4dbSFlorent Revest 			    (fmt[i + 2] != '4' && fmt[i + 2] != '6')) {
872d9c9e4dbSFlorent Revest 				err = -EINVAL;
873d9c9e4dbSFlorent Revest 				goto out;
874d9c9e4dbSFlorent Revest 			}
875d9c9e4dbSFlorent Revest 
87648cac3f4SFlorent Revest 			i += 2;
87748cac3f4SFlorent Revest 			if (!tmp_buf)
87848cac3f4SFlorent Revest 				goto nocopy_fmt;
87948cac3f4SFlorent Revest 
88048cac3f4SFlorent Revest 			sizeof_cur_ip = (fmt[i] == '4') ? 4 : 16;
88148cac3f4SFlorent Revest 			if (tmp_buf_end - tmp_buf < sizeof_cur_ip) {
882d9c9e4dbSFlorent Revest 				err = -ENOSPC;
88348cac3f4SFlorent Revest 				goto out;
884d9c9e4dbSFlorent Revest 			}
885d9c9e4dbSFlorent Revest 
886d9c9e4dbSFlorent Revest 			unsafe_ptr = (char *)(long)raw_args[num_spec];
88748cac3f4SFlorent Revest 			err = copy_from_kernel_nofault(cur_ip, unsafe_ptr,
88848cac3f4SFlorent Revest 						       sizeof_cur_ip);
889d9c9e4dbSFlorent Revest 			if (err < 0)
89048cac3f4SFlorent Revest 				memset(cur_ip, 0, sizeof_cur_ip);
891d9c9e4dbSFlorent Revest 
89248cac3f4SFlorent Revest 			/* hack: bstr_printf expects IP addresses to be
89348cac3f4SFlorent Revest 			 * pre-formatted as strings, ironically, the easiest way
89448cac3f4SFlorent Revest 			 * to do that is to call snprintf.
89548cac3f4SFlorent Revest 			 */
89648cac3f4SFlorent Revest 			ip_spec[2] = fmt[i - 1];
89748cac3f4SFlorent Revest 			ip_spec[3] = fmt[i];
89848cac3f4SFlorent Revest 			err = snprintf(tmp_buf, tmp_buf_end - tmp_buf,
89948cac3f4SFlorent Revest 				       ip_spec, &cur_ip);
90048cac3f4SFlorent Revest 
90148cac3f4SFlorent Revest 			tmp_buf += err + 1;
90248cac3f4SFlorent Revest 			num_spec++;
90348cac3f4SFlorent Revest 
90448cac3f4SFlorent Revest 			continue;
905d9c9e4dbSFlorent Revest 		} else if (fmt[i] == 's') {
906d9c9e4dbSFlorent Revest 			fmt_ptype = fmt[i];
907d9c9e4dbSFlorent Revest fmt_str:
908d9c9e4dbSFlorent Revest 			if (fmt[i + 1] != 0 &&
909d9c9e4dbSFlorent Revest 			    !isspace(fmt[i + 1]) &&
910d9c9e4dbSFlorent Revest 			    !ispunct(fmt[i + 1])) {
911d9c9e4dbSFlorent Revest 				err = -EINVAL;
912d9c9e4dbSFlorent Revest 				goto out;
913d9c9e4dbSFlorent Revest 			}
914d9c9e4dbSFlorent Revest 
91548cac3f4SFlorent Revest 			if (!tmp_buf)
91648cac3f4SFlorent Revest 				goto nocopy_fmt;
91748cac3f4SFlorent Revest 
91848cac3f4SFlorent Revest 			if (tmp_buf_end == tmp_buf) {
919d9c9e4dbSFlorent Revest 				err = -ENOSPC;
92048cac3f4SFlorent Revest 				goto out;
921d9c9e4dbSFlorent Revest 			}
922d9c9e4dbSFlorent Revest 
923d9c9e4dbSFlorent Revest 			unsafe_ptr = (char *)(long)raw_args[num_spec];
924d9c9e4dbSFlorent Revest 			err = bpf_trace_copy_string(tmp_buf, unsafe_ptr,
92548cac3f4SFlorent Revest 						    fmt_ptype,
92648cac3f4SFlorent Revest 						    tmp_buf_end - tmp_buf);
927d9c9e4dbSFlorent Revest 			if (err < 0) {
928d9c9e4dbSFlorent Revest 				tmp_buf[0] = '\0';
929d9c9e4dbSFlorent Revest 				err = 1;
930d9c9e4dbSFlorent Revest 			}
931d9c9e4dbSFlorent Revest 
932d9c9e4dbSFlorent Revest 			tmp_buf += err;
93348cac3f4SFlorent Revest 			num_spec++;
934d9c9e4dbSFlorent Revest 
93548cac3f4SFlorent Revest 			continue;
9363478cfcfSKuniyuki Iwashima 		} else if (fmt[i] == 'c') {
9373478cfcfSKuniyuki Iwashima 			if (!tmp_buf)
9383478cfcfSKuniyuki Iwashima 				goto nocopy_fmt;
9393478cfcfSKuniyuki Iwashima 
9403478cfcfSKuniyuki Iwashima 			if (tmp_buf_end == tmp_buf) {
9413478cfcfSKuniyuki Iwashima 				err = -ENOSPC;
9423478cfcfSKuniyuki Iwashima 				goto out;
9433478cfcfSKuniyuki Iwashima 			}
9443478cfcfSKuniyuki Iwashima 
9453478cfcfSKuniyuki Iwashima 			*tmp_buf = raw_args[num_spec];
9463478cfcfSKuniyuki Iwashima 			tmp_buf++;
9473478cfcfSKuniyuki Iwashima 			num_spec++;
9483478cfcfSKuniyuki Iwashima 
9493478cfcfSKuniyuki Iwashima 			continue;
950d9c9e4dbSFlorent Revest 		}
951d9c9e4dbSFlorent Revest 
95248cac3f4SFlorent Revest 		sizeof_cur_arg = sizeof(int);
953d9c9e4dbSFlorent Revest 
954d9c9e4dbSFlorent Revest 		if (fmt[i] == 'l') {
95548cac3f4SFlorent Revest 			sizeof_cur_arg = sizeof(long);
956d9c9e4dbSFlorent Revest 			i++;
957d9c9e4dbSFlorent Revest 		}
958d9c9e4dbSFlorent Revest 		if (fmt[i] == 'l') {
95948cac3f4SFlorent Revest 			sizeof_cur_arg = sizeof(long long);
960d9c9e4dbSFlorent Revest 			i++;
961d9c9e4dbSFlorent Revest 		}
962d9c9e4dbSFlorent Revest 
963d9c9e4dbSFlorent Revest 		if (fmt[i] != 'i' && fmt[i] != 'd' && fmt[i] != 'u' &&
964d9c9e4dbSFlorent Revest 		    fmt[i] != 'x' && fmt[i] != 'X') {
965d9c9e4dbSFlorent Revest 			err = -EINVAL;
96648cac3f4SFlorent Revest 			goto out;
967d9c9e4dbSFlorent Revest 		}
968d9c9e4dbSFlorent Revest 
96948cac3f4SFlorent Revest 		if (tmp_buf)
970d9c9e4dbSFlorent Revest 			cur_arg = raw_args[num_spec];
97148cac3f4SFlorent Revest nocopy_fmt:
97248cac3f4SFlorent Revest 		if (tmp_buf) {
97348cac3f4SFlorent Revest 			tmp_buf = PTR_ALIGN(tmp_buf, sizeof(u32));
97448cac3f4SFlorent Revest 			if (tmp_buf_end - tmp_buf < sizeof_cur_arg) {
97548cac3f4SFlorent Revest 				err = -ENOSPC;
97648cac3f4SFlorent Revest 				goto out;
97748cac3f4SFlorent Revest 			}
97848cac3f4SFlorent Revest 
97948cac3f4SFlorent Revest 			if (sizeof_cur_arg == 8) {
98048cac3f4SFlorent Revest 				*(u32 *)tmp_buf = *(u32 *)&cur_arg;
98148cac3f4SFlorent Revest 				*(u32 *)(tmp_buf + 4) = *((u32 *)&cur_arg + 1);
98248cac3f4SFlorent Revest 			} else {
98348cac3f4SFlorent Revest 				*(u32 *)tmp_buf = (u32)(long)cur_arg;
98448cac3f4SFlorent Revest 			}
98548cac3f4SFlorent Revest 			tmp_buf += sizeof_cur_arg;
986d9c9e4dbSFlorent Revest 		}
987d9c9e4dbSFlorent Revest 		num_spec++;
988d9c9e4dbSFlorent Revest 	}
989d9c9e4dbSFlorent Revest 
990d9c9e4dbSFlorent Revest 	err = 0;
991d9c9e4dbSFlorent Revest out:
99248cac3f4SFlorent Revest 	if (err)
99348cac3f4SFlorent Revest 		bpf_bprintf_cleanup();
994d9c9e4dbSFlorent Revest 	return err;
995d9c9e4dbSFlorent Revest }
996d9c9e4dbSFlorent Revest 
9977b15523aSFlorent Revest BPF_CALL_5(bpf_snprintf, char *, str, u32, str_size, char *, fmt,
9987b15523aSFlorent Revest 	   const void *, data, u32, data_len)
9997b15523aSFlorent Revest {
10007b15523aSFlorent Revest 	int err, num_args;
100148cac3f4SFlorent Revest 	u32 *bin_args;
10027b15523aSFlorent Revest 
1003335ff499SDave Marchevsky 	if (data_len % 8 || data_len > MAX_BPRINTF_VARARGS * 8 ||
10047b15523aSFlorent Revest 	    (data_len && !data))
10057b15523aSFlorent Revest 		return -EINVAL;
10067b15523aSFlorent Revest 	num_args = data_len / 8;
10077b15523aSFlorent Revest 
10087b15523aSFlorent Revest 	/* ARG_PTR_TO_CONST_STR guarantees that fmt is zero-terminated so we
10097b15523aSFlorent Revest 	 * can safely give an unbounded size.
10107b15523aSFlorent Revest 	 */
101148cac3f4SFlorent Revest 	err = bpf_bprintf_prepare(fmt, UINT_MAX, data, &bin_args, num_args);
10127b15523aSFlorent Revest 	if (err < 0)
10137b15523aSFlorent Revest 		return err;
10147b15523aSFlorent Revest 
101548cac3f4SFlorent Revest 	err = bstr_printf(str, str_size, fmt, bin_args);
10167b15523aSFlorent Revest 
101748cac3f4SFlorent Revest 	bpf_bprintf_cleanup();
10187b15523aSFlorent Revest 
10197b15523aSFlorent Revest 	return err + 1;
10207b15523aSFlorent Revest }
10217b15523aSFlorent Revest 
10227b15523aSFlorent Revest const struct bpf_func_proto bpf_snprintf_proto = {
10237b15523aSFlorent Revest 	.func		= bpf_snprintf,
10247b15523aSFlorent Revest 	.gpl_only	= true,
10257b15523aSFlorent Revest 	.ret_type	= RET_INTEGER,
10267b15523aSFlorent Revest 	.arg1_type	= ARG_PTR_TO_MEM_OR_NULL,
10277b15523aSFlorent Revest 	.arg2_type	= ARG_CONST_SIZE_OR_ZERO,
10287b15523aSFlorent Revest 	.arg3_type	= ARG_PTR_TO_CONST_STR,
10297b15523aSFlorent Revest 	.arg4_type	= ARG_PTR_TO_MEM_OR_NULL,
10307b15523aSFlorent Revest 	.arg5_type	= ARG_CONST_SIZE_OR_ZERO,
10317b15523aSFlorent Revest };
10327b15523aSFlorent Revest 
1033b00628b1SAlexei Starovoitov /* BPF map elements can contain 'struct bpf_timer'.
1034b00628b1SAlexei Starovoitov  * Such map owns all of its BPF timers.
1035b00628b1SAlexei Starovoitov  * 'struct bpf_timer' is allocated as part of map element allocation
1036b00628b1SAlexei Starovoitov  * and it's zero initialized.
1037b00628b1SAlexei Starovoitov  * That space is used to keep 'struct bpf_timer_kern'.
1038b00628b1SAlexei Starovoitov  * bpf_timer_init() allocates 'struct bpf_hrtimer', inits hrtimer, and
1039b00628b1SAlexei Starovoitov  * remembers 'struct bpf_map *' pointer it's part of.
1040b00628b1SAlexei Starovoitov  * bpf_timer_set_callback() increments prog refcnt and assign bpf callback_fn.
1041b00628b1SAlexei Starovoitov  * bpf_timer_start() arms the timer.
1042b00628b1SAlexei Starovoitov  * If user space reference to a map goes to zero at this point
1043b00628b1SAlexei Starovoitov  * ops->map_release_uref callback is responsible for cancelling the timers,
1044b00628b1SAlexei Starovoitov  * freeing their memory, and decrementing prog's refcnts.
1045b00628b1SAlexei Starovoitov  * bpf_timer_cancel() cancels the timer and decrements prog's refcnt.
1046b00628b1SAlexei Starovoitov  * Inner maps can contain bpf timers as well. ops->map_release_uref is
1047b00628b1SAlexei Starovoitov  * freeing the timers when inner map is replaced or deleted by user space.
1048b00628b1SAlexei Starovoitov  */
1049b00628b1SAlexei Starovoitov struct bpf_hrtimer {
1050b00628b1SAlexei Starovoitov 	struct hrtimer timer;
1051b00628b1SAlexei Starovoitov 	struct bpf_map *map;
1052b00628b1SAlexei Starovoitov 	struct bpf_prog *prog;
1053b00628b1SAlexei Starovoitov 	void __rcu *callback_fn;
1054b00628b1SAlexei Starovoitov 	void *value;
1055b00628b1SAlexei Starovoitov };
1056b00628b1SAlexei Starovoitov 
1057b00628b1SAlexei Starovoitov /* the actual struct hidden inside uapi struct bpf_timer */
1058b00628b1SAlexei Starovoitov struct bpf_timer_kern {
1059b00628b1SAlexei Starovoitov 	struct bpf_hrtimer *timer;
1060b00628b1SAlexei Starovoitov 	/* bpf_spin_lock is used here instead of spinlock_t to make
1061b00628b1SAlexei Starovoitov 	 * sure that it always fits into space resereved by struct bpf_timer
1062b00628b1SAlexei Starovoitov 	 * regardless of LOCKDEP and spinlock debug flags.
1063b00628b1SAlexei Starovoitov 	 */
1064b00628b1SAlexei Starovoitov 	struct bpf_spin_lock lock;
1065b00628b1SAlexei Starovoitov } __attribute__((aligned(8)));
1066b00628b1SAlexei Starovoitov 
1067b00628b1SAlexei Starovoitov static DEFINE_PER_CPU(struct bpf_hrtimer *, hrtimer_running);
1068b00628b1SAlexei Starovoitov 
1069b00628b1SAlexei Starovoitov static enum hrtimer_restart bpf_timer_cb(struct hrtimer *hrtimer)
1070b00628b1SAlexei Starovoitov {
1071b00628b1SAlexei Starovoitov 	struct bpf_hrtimer *t = container_of(hrtimer, struct bpf_hrtimer, timer);
1072b00628b1SAlexei Starovoitov 	struct bpf_map *map = t->map;
1073b00628b1SAlexei Starovoitov 	void *value = t->value;
1074102acbacSKees Cook 	bpf_callback_t callback_fn;
1075b00628b1SAlexei Starovoitov 	void *key;
1076b00628b1SAlexei Starovoitov 	u32 idx;
1077b00628b1SAlexei Starovoitov 
1078b00628b1SAlexei Starovoitov 	callback_fn = rcu_dereference_check(t->callback_fn, rcu_read_lock_bh_held());
1079b00628b1SAlexei Starovoitov 	if (!callback_fn)
1080b00628b1SAlexei Starovoitov 		goto out;
1081b00628b1SAlexei Starovoitov 
1082b00628b1SAlexei Starovoitov 	/* bpf_timer_cb() runs in hrtimer_run_softirq. It doesn't migrate and
1083b00628b1SAlexei Starovoitov 	 * cannot be preempted by another bpf_timer_cb() on the same cpu.
1084b00628b1SAlexei Starovoitov 	 * Remember the timer this callback is servicing to prevent
1085b00628b1SAlexei Starovoitov 	 * deadlock if callback_fn() calls bpf_timer_cancel() or
1086b00628b1SAlexei Starovoitov 	 * bpf_map_delete_elem() on the same timer.
1087b00628b1SAlexei Starovoitov 	 */
1088b00628b1SAlexei Starovoitov 	this_cpu_write(hrtimer_running, t);
1089b00628b1SAlexei Starovoitov 	if (map->map_type == BPF_MAP_TYPE_ARRAY) {
1090b00628b1SAlexei Starovoitov 		struct bpf_array *array = container_of(map, struct bpf_array, map);
1091b00628b1SAlexei Starovoitov 
1092b00628b1SAlexei Starovoitov 		/* compute the key */
1093b00628b1SAlexei Starovoitov 		idx = ((char *)value - array->value) / array->elem_size;
1094b00628b1SAlexei Starovoitov 		key = &idx;
1095b00628b1SAlexei Starovoitov 	} else { /* hash or lru */
1096b00628b1SAlexei Starovoitov 		key = value - round_up(map->key_size, 8);
1097b00628b1SAlexei Starovoitov 	}
1098b00628b1SAlexei Starovoitov 
1099102acbacSKees Cook 	callback_fn((u64)(long)map, (u64)(long)key, (u64)(long)value, 0, 0);
1100bfc6bb74SAlexei Starovoitov 	/* The verifier checked that return value is zero. */
1101b00628b1SAlexei Starovoitov 
1102b00628b1SAlexei Starovoitov 	this_cpu_write(hrtimer_running, NULL);
1103b00628b1SAlexei Starovoitov out:
1104b00628b1SAlexei Starovoitov 	return HRTIMER_NORESTART;
1105b00628b1SAlexei Starovoitov }
1106b00628b1SAlexei Starovoitov 
1107b00628b1SAlexei Starovoitov BPF_CALL_3(bpf_timer_init, struct bpf_timer_kern *, timer, struct bpf_map *, map,
1108b00628b1SAlexei Starovoitov 	   u64, flags)
1109b00628b1SAlexei Starovoitov {
1110b00628b1SAlexei Starovoitov 	clockid_t clockid = flags & (MAX_CLOCKS - 1);
1111b00628b1SAlexei Starovoitov 	struct bpf_hrtimer *t;
1112b00628b1SAlexei Starovoitov 	int ret = 0;
1113b00628b1SAlexei Starovoitov 
1114b00628b1SAlexei Starovoitov 	BUILD_BUG_ON(MAX_CLOCKS != 16);
1115b00628b1SAlexei Starovoitov 	BUILD_BUG_ON(sizeof(struct bpf_timer_kern) > sizeof(struct bpf_timer));
1116b00628b1SAlexei Starovoitov 	BUILD_BUG_ON(__alignof__(struct bpf_timer_kern) != __alignof__(struct bpf_timer));
1117b00628b1SAlexei Starovoitov 
1118b00628b1SAlexei Starovoitov 	if (in_nmi())
1119b00628b1SAlexei Starovoitov 		return -EOPNOTSUPP;
1120b00628b1SAlexei Starovoitov 
1121b00628b1SAlexei Starovoitov 	if (flags >= MAX_CLOCKS ||
1122b00628b1SAlexei Starovoitov 	    /* similar to timerfd except _ALARM variants are not supported */
1123b00628b1SAlexei Starovoitov 	    (clockid != CLOCK_MONOTONIC &&
1124b00628b1SAlexei Starovoitov 	     clockid != CLOCK_REALTIME &&
1125b00628b1SAlexei Starovoitov 	     clockid != CLOCK_BOOTTIME))
1126b00628b1SAlexei Starovoitov 		return -EINVAL;
1127b00628b1SAlexei Starovoitov 	__bpf_spin_lock_irqsave(&timer->lock);
1128b00628b1SAlexei Starovoitov 	t = timer->timer;
1129b00628b1SAlexei Starovoitov 	if (t) {
1130b00628b1SAlexei Starovoitov 		ret = -EBUSY;
1131b00628b1SAlexei Starovoitov 		goto out;
1132b00628b1SAlexei Starovoitov 	}
1133b00628b1SAlexei Starovoitov 	if (!atomic64_read(&map->usercnt)) {
1134b00628b1SAlexei Starovoitov 		/* maps with timers must be either held by user space
1135b00628b1SAlexei Starovoitov 		 * or pinned in bpffs.
1136b00628b1SAlexei Starovoitov 		 */
1137b00628b1SAlexei Starovoitov 		ret = -EPERM;
1138b00628b1SAlexei Starovoitov 		goto out;
1139b00628b1SAlexei Starovoitov 	}
1140b00628b1SAlexei Starovoitov 	/* allocate hrtimer via map_kmalloc to use memcg accounting */
1141b00628b1SAlexei Starovoitov 	t = bpf_map_kmalloc_node(map, sizeof(*t), GFP_ATOMIC, map->numa_node);
1142b00628b1SAlexei Starovoitov 	if (!t) {
1143b00628b1SAlexei Starovoitov 		ret = -ENOMEM;
1144b00628b1SAlexei Starovoitov 		goto out;
1145b00628b1SAlexei Starovoitov 	}
1146b00628b1SAlexei Starovoitov 	t->value = (void *)timer - map->timer_off;
1147b00628b1SAlexei Starovoitov 	t->map = map;
1148b00628b1SAlexei Starovoitov 	t->prog = NULL;
1149b00628b1SAlexei Starovoitov 	rcu_assign_pointer(t->callback_fn, NULL);
1150b00628b1SAlexei Starovoitov 	hrtimer_init(&t->timer, clockid, HRTIMER_MODE_REL_SOFT);
1151b00628b1SAlexei Starovoitov 	t->timer.function = bpf_timer_cb;
1152b00628b1SAlexei Starovoitov 	timer->timer = t;
1153b00628b1SAlexei Starovoitov out:
1154b00628b1SAlexei Starovoitov 	__bpf_spin_unlock_irqrestore(&timer->lock);
1155b00628b1SAlexei Starovoitov 	return ret;
1156b00628b1SAlexei Starovoitov }
1157b00628b1SAlexei Starovoitov 
1158b00628b1SAlexei Starovoitov static const struct bpf_func_proto bpf_timer_init_proto = {
1159b00628b1SAlexei Starovoitov 	.func		= bpf_timer_init,
1160b00628b1SAlexei Starovoitov 	.gpl_only	= true,
1161b00628b1SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
1162b00628b1SAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_TIMER,
1163b00628b1SAlexei Starovoitov 	.arg2_type	= ARG_CONST_MAP_PTR,
1164b00628b1SAlexei Starovoitov 	.arg3_type	= ARG_ANYTHING,
1165b00628b1SAlexei Starovoitov };
1166b00628b1SAlexei Starovoitov 
1167b00628b1SAlexei Starovoitov BPF_CALL_3(bpf_timer_set_callback, struct bpf_timer_kern *, timer, void *, callback_fn,
1168b00628b1SAlexei Starovoitov 	   struct bpf_prog_aux *, aux)
1169b00628b1SAlexei Starovoitov {
1170b00628b1SAlexei Starovoitov 	struct bpf_prog *prev, *prog = aux->prog;
1171b00628b1SAlexei Starovoitov 	struct bpf_hrtimer *t;
1172b00628b1SAlexei Starovoitov 	int ret = 0;
1173b00628b1SAlexei Starovoitov 
1174b00628b1SAlexei Starovoitov 	if (in_nmi())
1175b00628b1SAlexei Starovoitov 		return -EOPNOTSUPP;
1176b00628b1SAlexei Starovoitov 	__bpf_spin_lock_irqsave(&timer->lock);
1177b00628b1SAlexei Starovoitov 	t = timer->timer;
1178b00628b1SAlexei Starovoitov 	if (!t) {
1179b00628b1SAlexei Starovoitov 		ret = -EINVAL;
1180b00628b1SAlexei Starovoitov 		goto out;
1181b00628b1SAlexei Starovoitov 	}
1182b00628b1SAlexei Starovoitov 	if (!atomic64_read(&t->map->usercnt)) {
1183b00628b1SAlexei Starovoitov 		/* maps with timers must be either held by user space
1184b00628b1SAlexei Starovoitov 		 * or pinned in bpffs. Otherwise timer might still be
1185b00628b1SAlexei Starovoitov 		 * running even when bpf prog is detached and user space
1186b00628b1SAlexei Starovoitov 		 * is gone, since map_release_uref won't ever be called.
1187b00628b1SAlexei Starovoitov 		 */
1188b00628b1SAlexei Starovoitov 		ret = -EPERM;
1189b00628b1SAlexei Starovoitov 		goto out;
1190b00628b1SAlexei Starovoitov 	}
1191b00628b1SAlexei Starovoitov 	prev = t->prog;
1192b00628b1SAlexei Starovoitov 	if (prev != prog) {
1193b00628b1SAlexei Starovoitov 		/* Bump prog refcnt once. Every bpf_timer_set_callback()
1194b00628b1SAlexei Starovoitov 		 * can pick different callback_fn-s within the same prog.
1195b00628b1SAlexei Starovoitov 		 */
1196b00628b1SAlexei Starovoitov 		prog = bpf_prog_inc_not_zero(prog);
1197b00628b1SAlexei Starovoitov 		if (IS_ERR(prog)) {
1198b00628b1SAlexei Starovoitov 			ret = PTR_ERR(prog);
1199b00628b1SAlexei Starovoitov 			goto out;
1200b00628b1SAlexei Starovoitov 		}
1201b00628b1SAlexei Starovoitov 		if (prev)
1202b00628b1SAlexei Starovoitov 			/* Drop prev prog refcnt when swapping with new prog */
1203b00628b1SAlexei Starovoitov 			bpf_prog_put(prev);
1204b00628b1SAlexei Starovoitov 		t->prog = prog;
1205b00628b1SAlexei Starovoitov 	}
1206b00628b1SAlexei Starovoitov 	rcu_assign_pointer(t->callback_fn, callback_fn);
1207b00628b1SAlexei Starovoitov out:
1208b00628b1SAlexei Starovoitov 	__bpf_spin_unlock_irqrestore(&timer->lock);
1209b00628b1SAlexei Starovoitov 	return ret;
1210b00628b1SAlexei Starovoitov }
1211b00628b1SAlexei Starovoitov 
1212b00628b1SAlexei Starovoitov static const struct bpf_func_proto bpf_timer_set_callback_proto = {
1213b00628b1SAlexei Starovoitov 	.func		= bpf_timer_set_callback,
1214b00628b1SAlexei Starovoitov 	.gpl_only	= true,
1215b00628b1SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
1216b00628b1SAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_TIMER,
1217b00628b1SAlexei Starovoitov 	.arg2_type	= ARG_PTR_TO_FUNC,
1218b00628b1SAlexei Starovoitov };
1219b00628b1SAlexei Starovoitov 
1220b00628b1SAlexei Starovoitov BPF_CALL_3(bpf_timer_start, struct bpf_timer_kern *, timer, u64, nsecs, u64, flags)
1221b00628b1SAlexei Starovoitov {
1222b00628b1SAlexei Starovoitov 	struct bpf_hrtimer *t;
1223b00628b1SAlexei Starovoitov 	int ret = 0;
1224b00628b1SAlexei Starovoitov 
1225b00628b1SAlexei Starovoitov 	if (in_nmi())
1226b00628b1SAlexei Starovoitov 		return -EOPNOTSUPP;
1227b00628b1SAlexei Starovoitov 	if (flags)
1228b00628b1SAlexei Starovoitov 		return -EINVAL;
1229b00628b1SAlexei Starovoitov 	__bpf_spin_lock_irqsave(&timer->lock);
1230b00628b1SAlexei Starovoitov 	t = timer->timer;
1231b00628b1SAlexei Starovoitov 	if (!t || !t->prog) {
1232b00628b1SAlexei Starovoitov 		ret = -EINVAL;
1233b00628b1SAlexei Starovoitov 		goto out;
1234b00628b1SAlexei Starovoitov 	}
1235b00628b1SAlexei Starovoitov 	hrtimer_start(&t->timer, ns_to_ktime(nsecs), HRTIMER_MODE_REL_SOFT);
1236b00628b1SAlexei Starovoitov out:
1237b00628b1SAlexei Starovoitov 	__bpf_spin_unlock_irqrestore(&timer->lock);
1238b00628b1SAlexei Starovoitov 	return ret;
1239b00628b1SAlexei Starovoitov }
1240b00628b1SAlexei Starovoitov 
1241b00628b1SAlexei Starovoitov static const struct bpf_func_proto bpf_timer_start_proto = {
1242b00628b1SAlexei Starovoitov 	.func		= bpf_timer_start,
1243b00628b1SAlexei Starovoitov 	.gpl_only	= true,
1244b00628b1SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
1245b00628b1SAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_TIMER,
1246b00628b1SAlexei Starovoitov 	.arg2_type	= ARG_ANYTHING,
1247b00628b1SAlexei Starovoitov 	.arg3_type	= ARG_ANYTHING,
1248b00628b1SAlexei Starovoitov };
1249b00628b1SAlexei Starovoitov 
1250b00628b1SAlexei Starovoitov static void drop_prog_refcnt(struct bpf_hrtimer *t)
1251b00628b1SAlexei Starovoitov {
1252b00628b1SAlexei Starovoitov 	struct bpf_prog *prog = t->prog;
1253b00628b1SAlexei Starovoitov 
1254b00628b1SAlexei Starovoitov 	if (prog) {
1255b00628b1SAlexei Starovoitov 		bpf_prog_put(prog);
1256b00628b1SAlexei Starovoitov 		t->prog = NULL;
1257b00628b1SAlexei Starovoitov 		rcu_assign_pointer(t->callback_fn, NULL);
1258b00628b1SAlexei Starovoitov 	}
1259b00628b1SAlexei Starovoitov }
1260b00628b1SAlexei Starovoitov 
1261b00628b1SAlexei Starovoitov BPF_CALL_1(bpf_timer_cancel, struct bpf_timer_kern *, timer)
1262b00628b1SAlexei Starovoitov {
1263b00628b1SAlexei Starovoitov 	struct bpf_hrtimer *t;
1264b00628b1SAlexei Starovoitov 	int ret = 0;
1265b00628b1SAlexei Starovoitov 
1266b00628b1SAlexei Starovoitov 	if (in_nmi())
1267b00628b1SAlexei Starovoitov 		return -EOPNOTSUPP;
1268b00628b1SAlexei Starovoitov 	__bpf_spin_lock_irqsave(&timer->lock);
1269b00628b1SAlexei Starovoitov 	t = timer->timer;
1270b00628b1SAlexei Starovoitov 	if (!t) {
1271b00628b1SAlexei Starovoitov 		ret = -EINVAL;
1272b00628b1SAlexei Starovoitov 		goto out;
1273b00628b1SAlexei Starovoitov 	}
1274b00628b1SAlexei Starovoitov 	if (this_cpu_read(hrtimer_running) == t) {
1275b00628b1SAlexei Starovoitov 		/* If bpf callback_fn is trying to bpf_timer_cancel()
1276b00628b1SAlexei Starovoitov 		 * its own timer the hrtimer_cancel() will deadlock
1277b00628b1SAlexei Starovoitov 		 * since it waits for callback_fn to finish
1278b00628b1SAlexei Starovoitov 		 */
1279b00628b1SAlexei Starovoitov 		ret = -EDEADLK;
1280b00628b1SAlexei Starovoitov 		goto out;
1281b00628b1SAlexei Starovoitov 	}
1282b00628b1SAlexei Starovoitov 	drop_prog_refcnt(t);
1283b00628b1SAlexei Starovoitov out:
1284b00628b1SAlexei Starovoitov 	__bpf_spin_unlock_irqrestore(&timer->lock);
1285b00628b1SAlexei Starovoitov 	/* Cancel the timer and wait for associated callback to finish
1286b00628b1SAlexei Starovoitov 	 * if it was running.
1287b00628b1SAlexei Starovoitov 	 */
1288b00628b1SAlexei Starovoitov 	ret = ret ?: hrtimer_cancel(&t->timer);
1289b00628b1SAlexei Starovoitov 	return ret;
1290b00628b1SAlexei Starovoitov }
1291b00628b1SAlexei Starovoitov 
1292b00628b1SAlexei Starovoitov static const struct bpf_func_proto bpf_timer_cancel_proto = {
1293b00628b1SAlexei Starovoitov 	.func		= bpf_timer_cancel,
1294b00628b1SAlexei Starovoitov 	.gpl_only	= true,
1295b00628b1SAlexei Starovoitov 	.ret_type	= RET_INTEGER,
1296b00628b1SAlexei Starovoitov 	.arg1_type	= ARG_PTR_TO_TIMER,
1297b00628b1SAlexei Starovoitov };
1298b00628b1SAlexei Starovoitov 
1299b00628b1SAlexei Starovoitov /* This function is called by map_delete/update_elem for individual element and
1300b00628b1SAlexei Starovoitov  * by ops->map_release_uref when the user space reference to a map reaches zero.
1301b00628b1SAlexei Starovoitov  */
1302b00628b1SAlexei Starovoitov void bpf_timer_cancel_and_free(void *val)
1303b00628b1SAlexei Starovoitov {
1304b00628b1SAlexei Starovoitov 	struct bpf_timer_kern *timer = val;
1305b00628b1SAlexei Starovoitov 	struct bpf_hrtimer *t;
1306b00628b1SAlexei Starovoitov 
1307b00628b1SAlexei Starovoitov 	/* Performance optimization: read timer->timer without lock first. */
1308b00628b1SAlexei Starovoitov 	if (!READ_ONCE(timer->timer))
1309b00628b1SAlexei Starovoitov 		return;
1310b00628b1SAlexei Starovoitov 
1311b00628b1SAlexei Starovoitov 	__bpf_spin_lock_irqsave(&timer->lock);
1312b00628b1SAlexei Starovoitov 	/* re-read it under lock */
1313b00628b1SAlexei Starovoitov 	t = timer->timer;
1314b00628b1SAlexei Starovoitov 	if (!t)
1315b00628b1SAlexei Starovoitov 		goto out;
1316b00628b1SAlexei Starovoitov 	drop_prog_refcnt(t);
1317b00628b1SAlexei Starovoitov 	/* The subsequent bpf_timer_start/cancel() helpers won't be able to use
1318b00628b1SAlexei Starovoitov 	 * this timer, since it won't be initialized.
1319b00628b1SAlexei Starovoitov 	 */
1320b00628b1SAlexei Starovoitov 	timer->timer = NULL;
1321b00628b1SAlexei Starovoitov out:
1322b00628b1SAlexei Starovoitov 	__bpf_spin_unlock_irqrestore(&timer->lock);
1323b00628b1SAlexei Starovoitov 	if (!t)
1324b00628b1SAlexei Starovoitov 		return;
1325b00628b1SAlexei Starovoitov 	/* Cancel the timer and wait for callback to complete if it was running.
1326b00628b1SAlexei Starovoitov 	 * If hrtimer_cancel() can be safely called it's safe to call kfree(t)
1327b00628b1SAlexei Starovoitov 	 * right after for both preallocated and non-preallocated maps.
1328b00628b1SAlexei Starovoitov 	 * The timer->timer = NULL was already done and no code path can
1329b00628b1SAlexei Starovoitov 	 * see address 't' anymore.
1330b00628b1SAlexei Starovoitov 	 *
1331b00628b1SAlexei Starovoitov 	 * Check that bpf_map_delete/update_elem() wasn't called from timer
1332b00628b1SAlexei Starovoitov 	 * callback_fn. In such case don't call hrtimer_cancel() (since it will
1333b00628b1SAlexei Starovoitov 	 * deadlock) and don't call hrtimer_try_to_cancel() (since it will just
1334b00628b1SAlexei Starovoitov 	 * return -1). Though callback_fn is still running on this cpu it's
1335b00628b1SAlexei Starovoitov 	 * safe to do kfree(t) because bpf_timer_cb() read everything it needed
1336b00628b1SAlexei Starovoitov 	 * from 't'. The bpf subprog callback_fn won't be able to access 't',
1337b00628b1SAlexei Starovoitov 	 * since timer->timer = NULL was already done. The timer will be
1338b00628b1SAlexei Starovoitov 	 * effectively cancelled because bpf_timer_cb() will return
1339b00628b1SAlexei Starovoitov 	 * HRTIMER_NORESTART.
1340b00628b1SAlexei Starovoitov 	 */
1341b00628b1SAlexei Starovoitov 	if (this_cpu_read(hrtimer_running) != t)
1342b00628b1SAlexei Starovoitov 		hrtimer_cancel(&t->timer);
1343b00628b1SAlexei Starovoitov 	kfree(t);
1344b00628b1SAlexei Starovoitov }
1345b00628b1SAlexei Starovoitov 
1346f470378cSJohn Fastabend const struct bpf_func_proto bpf_get_current_task_proto __weak;
1347a396eda5SDaniel Xu const struct bpf_func_proto bpf_get_current_task_btf_proto __weak;
1348f470378cSJohn Fastabend const struct bpf_func_proto bpf_probe_read_user_proto __weak;
1349f470378cSJohn Fastabend const struct bpf_func_proto bpf_probe_read_user_str_proto __weak;
1350f470378cSJohn Fastabend const struct bpf_func_proto bpf_probe_read_kernel_proto __weak;
1351f470378cSJohn Fastabend const struct bpf_func_proto bpf_probe_read_kernel_str_proto __weak;
1352dd6e10fbSDaniel Xu const struct bpf_func_proto bpf_task_pt_regs_proto __weak;
1353f470378cSJohn Fastabend 
13546890896bSStanislav Fomichev const struct bpf_func_proto *
13556890896bSStanislav Fomichev bpf_base_func_proto(enum bpf_func_id func_id)
13566890896bSStanislav Fomichev {
13576890896bSStanislav Fomichev 	switch (func_id) {
13586890896bSStanislav Fomichev 	case BPF_FUNC_map_lookup_elem:
13596890896bSStanislav Fomichev 		return &bpf_map_lookup_elem_proto;
13606890896bSStanislav Fomichev 	case BPF_FUNC_map_update_elem:
13616890896bSStanislav Fomichev 		return &bpf_map_update_elem_proto;
13626890896bSStanislav Fomichev 	case BPF_FUNC_map_delete_elem:
13636890896bSStanislav Fomichev 		return &bpf_map_delete_elem_proto;
13646890896bSStanislav Fomichev 	case BPF_FUNC_map_push_elem:
13656890896bSStanislav Fomichev 		return &bpf_map_push_elem_proto;
13666890896bSStanislav Fomichev 	case BPF_FUNC_map_pop_elem:
13676890896bSStanislav Fomichev 		return &bpf_map_pop_elem_proto;
13686890896bSStanislav Fomichev 	case BPF_FUNC_map_peek_elem:
13696890896bSStanislav Fomichev 		return &bpf_map_peek_elem_proto;
13706890896bSStanislav Fomichev 	case BPF_FUNC_get_prandom_u32:
13716890896bSStanislav Fomichev 		return &bpf_get_prandom_u32_proto;
13726890896bSStanislav Fomichev 	case BPF_FUNC_get_smp_processor_id:
13736890896bSStanislav Fomichev 		return &bpf_get_raw_smp_processor_id_proto;
13746890896bSStanislav Fomichev 	case BPF_FUNC_get_numa_node_id:
13756890896bSStanislav Fomichev 		return &bpf_get_numa_node_id_proto;
13766890896bSStanislav Fomichev 	case BPF_FUNC_tail_call:
13776890896bSStanislav Fomichev 		return &bpf_tail_call_proto;
13786890896bSStanislav Fomichev 	case BPF_FUNC_ktime_get_ns:
13796890896bSStanislav Fomichev 		return &bpf_ktime_get_ns_proto;
138071d19214SMaciej Żenczykowski 	case BPF_FUNC_ktime_get_boot_ns:
138171d19214SMaciej Żenczykowski 		return &bpf_ktime_get_boot_ns_proto;
1382457f4436SAndrii Nakryiko 	case BPF_FUNC_ringbuf_output:
1383457f4436SAndrii Nakryiko 		return &bpf_ringbuf_output_proto;
1384457f4436SAndrii Nakryiko 	case BPF_FUNC_ringbuf_reserve:
1385457f4436SAndrii Nakryiko 		return &bpf_ringbuf_reserve_proto;
1386457f4436SAndrii Nakryiko 	case BPF_FUNC_ringbuf_submit:
1387457f4436SAndrii Nakryiko 		return &bpf_ringbuf_submit_proto;
1388457f4436SAndrii Nakryiko 	case BPF_FUNC_ringbuf_discard:
1389457f4436SAndrii Nakryiko 		return &bpf_ringbuf_discard_proto;
1390457f4436SAndrii Nakryiko 	case BPF_FUNC_ringbuf_query:
1391457f4436SAndrii Nakryiko 		return &bpf_ringbuf_query_proto;
139269c087baSYonghong Song 	case BPF_FUNC_for_each_map_elem:
139369c087baSYonghong Song 		return &bpf_for_each_map_elem_proto;
1394e6f2dd0fSJoanne Koong 	case BPF_FUNC_loop:
1395e6f2dd0fSJoanne Koong 		return &bpf_loop_proto;
1396c5fb1993SHou Tao 	case BPF_FUNC_strncmp:
1397c5fb1993SHou Tao 		return &bpf_strncmp_proto;
13986890896bSStanislav Fomichev 	default:
13996890896bSStanislav Fomichev 		break;
14006890896bSStanislav Fomichev 	}
14016890896bSStanislav Fomichev 
14022c78ee89SAlexei Starovoitov 	if (!bpf_capable())
14036890896bSStanislav Fomichev 		return NULL;
14046890896bSStanislav Fomichev 
14056890896bSStanislav Fomichev 	switch (func_id) {
14066890896bSStanislav Fomichev 	case BPF_FUNC_spin_lock:
14076890896bSStanislav Fomichev 		return &bpf_spin_lock_proto;
14086890896bSStanislav Fomichev 	case BPF_FUNC_spin_unlock:
14096890896bSStanislav Fomichev 		return &bpf_spin_unlock_proto;
14106890896bSStanislav Fomichev 	case BPF_FUNC_jiffies64:
14116890896bSStanislav Fomichev 		return &bpf_jiffies64_proto;
1412b7906b70SAndrii Nakryiko 	case BPF_FUNC_per_cpu_ptr:
1413eaa6bcb7SHao Luo 		return &bpf_per_cpu_ptr_proto;
1414b7906b70SAndrii Nakryiko 	case BPF_FUNC_this_cpu_ptr:
141563d9b80dSHao Luo 		return &bpf_this_cpu_ptr_proto;
1416b00628b1SAlexei Starovoitov 	case BPF_FUNC_timer_init:
1417b00628b1SAlexei Starovoitov 		return &bpf_timer_init_proto;
1418b00628b1SAlexei Starovoitov 	case BPF_FUNC_timer_set_callback:
1419b00628b1SAlexei Starovoitov 		return &bpf_timer_set_callback_proto;
1420b00628b1SAlexei Starovoitov 	case BPF_FUNC_timer_start:
1421b00628b1SAlexei Starovoitov 		return &bpf_timer_start_proto;
1422b00628b1SAlexei Starovoitov 	case BPF_FUNC_timer_cancel:
1423b00628b1SAlexei Starovoitov 		return &bpf_timer_cancel_proto;
14246890896bSStanislav Fomichev 	default:
1425f470378cSJohn Fastabend 		break;
1426f470378cSJohn Fastabend 	}
1427f470378cSJohn Fastabend 
1428f470378cSJohn Fastabend 	if (!perfmon_capable())
1429f470378cSJohn Fastabend 		return NULL;
1430f470378cSJohn Fastabend 
1431f470378cSJohn Fastabend 	switch (func_id) {
143261ca36c8STobias Klauser 	case BPF_FUNC_trace_printk:
143361ca36c8STobias Klauser 		return bpf_get_trace_printk_proto();
1434f470378cSJohn Fastabend 	case BPF_FUNC_get_current_task:
1435f470378cSJohn Fastabend 		return &bpf_get_current_task_proto;
1436a396eda5SDaniel Xu 	case BPF_FUNC_get_current_task_btf:
1437a396eda5SDaniel Xu 		return &bpf_get_current_task_btf_proto;
1438f470378cSJohn Fastabend 	case BPF_FUNC_probe_read_user:
1439f470378cSJohn Fastabend 		return &bpf_probe_read_user_proto;
1440f470378cSJohn Fastabend 	case BPF_FUNC_probe_read_kernel:
144171330842SDaniel Borkmann 		return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
1442ff40e510SDaniel Borkmann 		       NULL : &bpf_probe_read_kernel_proto;
1443f470378cSJohn Fastabend 	case BPF_FUNC_probe_read_user_str:
1444f470378cSJohn Fastabend 		return &bpf_probe_read_user_str_proto;
1445f470378cSJohn Fastabend 	case BPF_FUNC_probe_read_kernel_str:
144671330842SDaniel Borkmann 		return security_locked_down(LOCKDOWN_BPF_READ_KERNEL) < 0 ?
1447ff40e510SDaniel Borkmann 		       NULL : &bpf_probe_read_kernel_str_proto;
144861ca36c8STobias Klauser 	case BPF_FUNC_snprintf_btf:
144961ca36c8STobias Klauser 		return &bpf_snprintf_btf_proto;
14507b15523aSFlorent Revest 	case BPF_FUNC_snprintf:
14517b15523aSFlorent Revest 		return &bpf_snprintf_proto;
1452dd6e10fbSDaniel Xu 	case BPF_FUNC_task_pt_regs:
1453dd6e10fbSDaniel Xu 		return &bpf_task_pt_regs_proto;
145410aceb62SDave Marchevsky 	case BPF_FUNC_trace_vprintk:
145510aceb62SDave Marchevsky 		return bpf_get_trace_vprintk_proto();
1456f470378cSJohn Fastabend 	default:
14576890896bSStanislav Fomichev 		return NULL;
14586890896bSStanislav Fomichev 	}
14596890896bSStanislav Fomichev }
1460