xref: /linux/tools/testing/selftests/bpf/progs/verifier_global_subprogs.c (revision 36ec807b627b4c0a0a382f0ae48eac7187d14b2b)
1e8a339b5SAndrii Nakryiko // SPDX-License-Identifier: GPL-2.0
2e8a339b5SAndrii Nakryiko /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
3e8a339b5SAndrii Nakryiko 
40a0ffcacSAndrii Nakryiko #include <vmlinux.h>
5e8a339b5SAndrii Nakryiko #include <bpf/bpf_helpers.h>
6989410cdSAndrii Nakryiko #include <bpf/bpf_tracing.h>
7e8a339b5SAndrii Nakryiko #include "bpf_misc.h"
80a0ffcacSAndrii Nakryiko #include "xdp_metadata.h"
90a0ffcacSAndrii Nakryiko #include "bpf_kfuncs.h"
10e8a339b5SAndrii Nakryiko 
11*cd3fc3b9SJose E. Marchesi /* The compiler may be able to detect the access to uninitialized
12*cd3fc3b9SJose E. Marchesi    memory in the routines performing out of bound memory accesses and
13*cd3fc3b9SJose E. Marchesi    emit warnings about it.  This is the case of GCC. */
14*cd3fc3b9SJose E. Marchesi #if !defined(__clang__)
15*cd3fc3b9SJose E. Marchesi #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
16*cd3fc3b9SJose E. Marchesi #endif
17*cd3fc3b9SJose E. Marchesi 
18e8a339b5SAndrii Nakryiko int arr[1];
19e8a339b5SAndrii Nakryiko int unkn_idx;
20e72c1ccfSAndrii Nakryiko const volatile bool call_dead_subprog = false;
21e8a339b5SAndrii Nakryiko 
22e8a339b5SAndrii Nakryiko __noinline long global_bad(void)
23e8a339b5SAndrii Nakryiko {
24e8a339b5SAndrii Nakryiko 	return arr[unkn_idx]; /* BOOM */
25e8a339b5SAndrii Nakryiko }
26e8a339b5SAndrii Nakryiko 
27e8a339b5SAndrii Nakryiko __noinline long global_good(void)
28e8a339b5SAndrii Nakryiko {
29e8a339b5SAndrii Nakryiko 	return arr[0];
30e8a339b5SAndrii Nakryiko }
31e8a339b5SAndrii Nakryiko 
32e8a339b5SAndrii Nakryiko __noinline long global_calls_bad(void)
33e8a339b5SAndrii Nakryiko {
34e8a339b5SAndrii Nakryiko 	return global_good() + global_bad() /* does BOOM indirectly */;
35e8a339b5SAndrii Nakryiko }
36e8a339b5SAndrii Nakryiko 
37e8a339b5SAndrii Nakryiko __noinline long global_calls_good_only(void)
38e8a339b5SAndrii Nakryiko {
39e8a339b5SAndrii Nakryiko 	return global_good();
40e8a339b5SAndrii Nakryiko }
41e8a339b5SAndrii Nakryiko 
42e72c1ccfSAndrii Nakryiko __noinline long global_dead(void)
43e72c1ccfSAndrii Nakryiko {
44e72c1ccfSAndrii Nakryiko 	return arr[0] * 2;
45e72c1ccfSAndrii Nakryiko }
46e72c1ccfSAndrii Nakryiko 
47e8a339b5SAndrii Nakryiko SEC("?raw_tp")
48e8a339b5SAndrii Nakryiko __success __log_level(2)
49e8a339b5SAndrii Nakryiko /* main prog is validated completely first */
50e8a339b5SAndrii Nakryiko __msg("('global_calls_good_only') is global and assumed valid.")
51e8a339b5SAndrii Nakryiko /* eventually global_good() is transitively validated as well */
52e8a339b5SAndrii Nakryiko __msg("Validating global_good() func")
53e8a339b5SAndrii Nakryiko __msg("('global_good') is safe for any args that match its prototype")
54e8a339b5SAndrii Nakryiko int chained_global_func_calls_success(void)
55e8a339b5SAndrii Nakryiko {
56e72c1ccfSAndrii Nakryiko 	int sum = 0;
57e72c1ccfSAndrii Nakryiko 
58e72c1ccfSAndrii Nakryiko 	if (call_dead_subprog)
59e72c1ccfSAndrii Nakryiko 		sum += global_dead();
60e72c1ccfSAndrii Nakryiko 	return global_calls_good_only() + sum;
61e8a339b5SAndrii Nakryiko }
62e8a339b5SAndrii Nakryiko 
63e8a339b5SAndrii Nakryiko SEC("?raw_tp")
64e8a339b5SAndrii Nakryiko __failure __log_level(2)
65e8a339b5SAndrii Nakryiko /* main prog validated successfully first */
66e72c1ccfSAndrii Nakryiko __msg("('global_calls_bad') is global and assumed valid.")
67e8a339b5SAndrii Nakryiko /* eventually we validate global_bad() and fail */
68e8a339b5SAndrii Nakryiko __msg("Validating global_bad() func")
69e8a339b5SAndrii Nakryiko __msg("math between map_value pointer and register") /* BOOM */
70e8a339b5SAndrii Nakryiko int chained_global_func_calls_bad(void)
71e8a339b5SAndrii Nakryiko {
72e8a339b5SAndrii Nakryiko 	return global_calls_bad();
73e8a339b5SAndrii Nakryiko }
74e8a339b5SAndrii Nakryiko 
75e8a339b5SAndrii Nakryiko /* do out of bounds access forcing verifier to fail verification if this
76e8a339b5SAndrii Nakryiko  * global func is called
77e8a339b5SAndrii Nakryiko  */
78e8a339b5SAndrii Nakryiko __noinline int global_unsupp(const int *mem)
79e8a339b5SAndrii Nakryiko {
80e8a339b5SAndrii Nakryiko 	if (!mem)
81e8a339b5SAndrii Nakryiko 		return 0;
82e8a339b5SAndrii Nakryiko 	return mem[100]; /* BOOM */
83e8a339b5SAndrii Nakryiko }
84e8a339b5SAndrii Nakryiko 
85e8a339b5SAndrii Nakryiko const volatile bool skip_unsupp_global = true;
86e8a339b5SAndrii Nakryiko 
87e8a339b5SAndrii Nakryiko SEC("?raw_tp")
88e8a339b5SAndrii Nakryiko __success
89e8a339b5SAndrii Nakryiko int guarded_unsupp_global_called(void)
90e8a339b5SAndrii Nakryiko {
91e8a339b5SAndrii Nakryiko 	if (!skip_unsupp_global)
92e8a339b5SAndrii Nakryiko 		return global_unsupp(NULL);
93e8a339b5SAndrii Nakryiko 	return 0;
94e8a339b5SAndrii Nakryiko }
95e8a339b5SAndrii Nakryiko 
96e8a339b5SAndrii Nakryiko SEC("?raw_tp")
97e8a339b5SAndrii Nakryiko __failure __log_level(2)
98e8a339b5SAndrii Nakryiko __msg("Func#1 ('global_unsupp') is global and assumed valid.")
99e8a339b5SAndrii Nakryiko __msg("Validating global_unsupp() func#1...")
100e8a339b5SAndrii Nakryiko __msg("value is outside of the allowed memory range")
101e8a339b5SAndrii Nakryiko int unguarded_unsupp_global_called(void)
102e8a339b5SAndrii Nakryiko {
103e8a339b5SAndrii Nakryiko 	int x = 0;
104e8a339b5SAndrii Nakryiko 
105e8a339b5SAndrii Nakryiko 	return global_unsupp(&x);
106e8a339b5SAndrii Nakryiko }
107e8a339b5SAndrii Nakryiko 
1080a0ffcacSAndrii Nakryiko long stack[128];
1090a0ffcacSAndrii Nakryiko 
1100a0ffcacSAndrii Nakryiko __weak int subprog_nullable_ptr_bad(int *p)
1110a0ffcacSAndrii Nakryiko {
1120a0ffcacSAndrii Nakryiko 	return (*p) * 2; /* bad, missing null check */
1130a0ffcacSAndrii Nakryiko }
1140a0ffcacSAndrii Nakryiko 
1150a0ffcacSAndrii Nakryiko SEC("?raw_tp")
1160a0ffcacSAndrii Nakryiko __failure __log_level(2)
1170a0ffcacSAndrii Nakryiko __msg("invalid mem access 'mem_or_null'")
1180a0ffcacSAndrii Nakryiko int arg_tag_nullable_ptr_fail(void *ctx)
1190a0ffcacSAndrii Nakryiko {
1200a0ffcacSAndrii Nakryiko 	int x = 42;
1210a0ffcacSAndrii Nakryiko 
1220a0ffcacSAndrii Nakryiko 	return subprog_nullable_ptr_bad(&x);
1230a0ffcacSAndrii Nakryiko }
1240a0ffcacSAndrii Nakryiko 
12563d5a33fSAndrii Nakryiko typedef struct {
12663d5a33fSAndrii Nakryiko 	int x;
12763d5a33fSAndrii Nakryiko } user_struct_t;
12863d5a33fSAndrii Nakryiko 
12963d5a33fSAndrii Nakryiko __noinline __weak int subprog_user_anon_mem(user_struct_t *t)
13063d5a33fSAndrii Nakryiko {
13163d5a33fSAndrii Nakryiko 	return t ? t->x : 0;
13263d5a33fSAndrii Nakryiko }
13363d5a33fSAndrii Nakryiko 
13463d5a33fSAndrii Nakryiko SEC("?tracepoint")
13563d5a33fSAndrii Nakryiko __failure __log_level(2)
13663d5a33fSAndrii Nakryiko __msg("invalid bpf_context access")
13763d5a33fSAndrii Nakryiko __msg("Caller passes invalid args into func#1 ('subprog_user_anon_mem')")
13863d5a33fSAndrii Nakryiko int anon_user_mem_invalid(void *ctx)
13963d5a33fSAndrii Nakryiko {
14063d5a33fSAndrii Nakryiko 	/* can't pass PTR_TO_CTX as user memory */
14163d5a33fSAndrii Nakryiko 	return subprog_user_anon_mem(ctx);
14263d5a33fSAndrii Nakryiko }
14363d5a33fSAndrii Nakryiko 
14463d5a33fSAndrii Nakryiko SEC("?tracepoint")
14563d5a33fSAndrii Nakryiko __success __log_level(2)
14663d5a33fSAndrii Nakryiko __msg("Func#1 ('subprog_user_anon_mem') is safe for any args that match its prototype")
14763d5a33fSAndrii Nakryiko int anon_user_mem_valid(void *ctx)
14863d5a33fSAndrii Nakryiko {
14963d5a33fSAndrii Nakryiko 	user_struct_t t = { .x = 42 };
15063d5a33fSAndrii Nakryiko 
15163d5a33fSAndrii Nakryiko 	return subprog_user_anon_mem(&t);
15263d5a33fSAndrii Nakryiko }
15363d5a33fSAndrii Nakryiko 
1540a0ffcacSAndrii Nakryiko __noinline __weak int subprog_nonnull_ptr_good(int *p1 __arg_nonnull, int *p2 __arg_nonnull)
1550a0ffcacSAndrii Nakryiko {
1560a0ffcacSAndrii Nakryiko 	return (*p1) * (*p2); /* good, no need for NULL checks */
1570a0ffcacSAndrii Nakryiko }
1580a0ffcacSAndrii Nakryiko 
1590a0ffcacSAndrii Nakryiko int x = 47;
1600a0ffcacSAndrii Nakryiko 
1610a0ffcacSAndrii Nakryiko SEC("?raw_tp")
1620a0ffcacSAndrii Nakryiko __success __log_level(2)
1630a0ffcacSAndrii Nakryiko int arg_tag_nonnull_ptr_good(void *ctx)
1640a0ffcacSAndrii Nakryiko {
1650a0ffcacSAndrii Nakryiko 	int y = 74;
1660a0ffcacSAndrii Nakryiko 
1670a0ffcacSAndrii Nakryiko 	return subprog_nonnull_ptr_good(&x, &y);
1680a0ffcacSAndrii Nakryiko }
1690a0ffcacSAndrii Nakryiko 
1700a0ffcacSAndrii Nakryiko /* this global subprog can be now called from many types of entry progs, each
1710a0ffcacSAndrii Nakryiko  * with different context type
1720a0ffcacSAndrii Nakryiko  */
1730a0ffcacSAndrii Nakryiko __weak int subprog_ctx_tag(void *ctx __arg_ctx)
1740a0ffcacSAndrii Nakryiko {
1750a0ffcacSAndrii Nakryiko 	return bpf_get_stack(ctx, stack, sizeof(stack), 0);
1760a0ffcacSAndrii Nakryiko }
1770a0ffcacSAndrii Nakryiko 
178989410cdSAndrii Nakryiko __weak int raw_tp_canonical(struct bpf_raw_tracepoint_args *ctx __arg_ctx)
179989410cdSAndrii Nakryiko {
180989410cdSAndrii Nakryiko 	return 0;
181989410cdSAndrii Nakryiko }
182989410cdSAndrii Nakryiko 
183989410cdSAndrii Nakryiko __weak int raw_tp_u64_array(u64 *ctx __arg_ctx)
184989410cdSAndrii Nakryiko {
185989410cdSAndrii Nakryiko 	return 0;
186989410cdSAndrii Nakryiko }
187989410cdSAndrii Nakryiko 
1880a0ffcacSAndrii Nakryiko SEC("?raw_tp")
1890a0ffcacSAndrii Nakryiko __success __log_level(2)
1900a0ffcacSAndrii Nakryiko int arg_tag_ctx_raw_tp(void *ctx)
1910a0ffcacSAndrii Nakryiko {
192989410cdSAndrii Nakryiko 	return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx);
193989410cdSAndrii Nakryiko }
194989410cdSAndrii Nakryiko 
195989410cdSAndrii Nakryiko SEC("?raw_tp.w")
196989410cdSAndrii Nakryiko __success __log_level(2)
197989410cdSAndrii Nakryiko int arg_tag_ctx_raw_tp_writable(void *ctx)
198989410cdSAndrii Nakryiko {
199989410cdSAndrii Nakryiko 	return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx);
200989410cdSAndrii Nakryiko }
201989410cdSAndrii Nakryiko 
202989410cdSAndrii Nakryiko SEC("?tp_btf/sys_enter")
203989410cdSAndrii Nakryiko __success __log_level(2)
204989410cdSAndrii Nakryiko int arg_tag_ctx_raw_tp_btf(void *ctx)
205989410cdSAndrii Nakryiko {
206989410cdSAndrii Nakryiko 	return subprog_ctx_tag(ctx) + raw_tp_canonical(ctx) + raw_tp_u64_array(ctx);
207989410cdSAndrii Nakryiko }
208989410cdSAndrii Nakryiko 
209989410cdSAndrii Nakryiko struct whatever { };
210989410cdSAndrii Nakryiko 
211989410cdSAndrii Nakryiko __weak int tp_whatever(struct whatever *ctx __arg_ctx)
212989410cdSAndrii Nakryiko {
213989410cdSAndrii Nakryiko 	return 0;
2140a0ffcacSAndrii Nakryiko }
2150a0ffcacSAndrii Nakryiko 
2160a0ffcacSAndrii Nakryiko SEC("?tp")
2170a0ffcacSAndrii Nakryiko __success __log_level(2)
2180a0ffcacSAndrii Nakryiko int arg_tag_ctx_tp(void *ctx)
2190a0ffcacSAndrii Nakryiko {
220989410cdSAndrii Nakryiko 	return subprog_ctx_tag(ctx) + tp_whatever(ctx);
221989410cdSAndrii Nakryiko }
222989410cdSAndrii Nakryiko 
223989410cdSAndrii Nakryiko __weak int kprobe_subprog_pt_regs(struct pt_regs *ctx __arg_ctx)
224989410cdSAndrii Nakryiko {
225989410cdSAndrii Nakryiko 	return 0;
226989410cdSAndrii Nakryiko }
227989410cdSAndrii Nakryiko 
228989410cdSAndrii Nakryiko __weak int kprobe_subprog_typedef(bpf_user_pt_regs_t *ctx __arg_ctx)
229989410cdSAndrii Nakryiko {
230989410cdSAndrii Nakryiko 	return 0;
2310a0ffcacSAndrii Nakryiko }
2320a0ffcacSAndrii Nakryiko 
2330a0ffcacSAndrii Nakryiko SEC("?kprobe")
2340a0ffcacSAndrii Nakryiko __success __log_level(2)
2350a0ffcacSAndrii Nakryiko int arg_tag_ctx_kprobe(void *ctx)
2360a0ffcacSAndrii Nakryiko {
237989410cdSAndrii Nakryiko 	return subprog_ctx_tag(ctx) +
238989410cdSAndrii Nakryiko 	       kprobe_subprog_pt_regs(ctx) +
239989410cdSAndrii Nakryiko 	       kprobe_subprog_typedef(ctx);
240989410cdSAndrii Nakryiko }
241989410cdSAndrii Nakryiko 
242989410cdSAndrii Nakryiko __weak int perf_subprog_regs(
243989410cdSAndrii Nakryiko #if defined(bpf_target_riscv)
244989410cdSAndrii Nakryiko 	struct user_regs_struct *ctx __arg_ctx
245989410cdSAndrii Nakryiko #elif defined(bpf_target_s390)
246989410cdSAndrii Nakryiko 	/* user_pt_regs typedef is anonymous struct, so only `void *` works */
247989410cdSAndrii Nakryiko 	void *ctx __arg_ctx
248989410cdSAndrii Nakryiko #elif defined(bpf_target_loongarch) || defined(bpf_target_arm64) || defined(bpf_target_powerpc)
249989410cdSAndrii Nakryiko 	struct user_pt_regs *ctx __arg_ctx
250989410cdSAndrii Nakryiko #else
251989410cdSAndrii Nakryiko 	struct pt_regs *ctx __arg_ctx
252989410cdSAndrii Nakryiko #endif
253989410cdSAndrii Nakryiko )
254989410cdSAndrii Nakryiko {
255989410cdSAndrii Nakryiko 	return 0;
256989410cdSAndrii Nakryiko }
257989410cdSAndrii Nakryiko 
258989410cdSAndrii Nakryiko __weak int perf_subprog_typedef(bpf_user_pt_regs_t *ctx __arg_ctx)
259989410cdSAndrii Nakryiko {
260989410cdSAndrii Nakryiko 	return 0;
261989410cdSAndrii Nakryiko }
262989410cdSAndrii Nakryiko 
263989410cdSAndrii Nakryiko __weak int perf_subprog_canonical(struct bpf_perf_event_data *ctx __arg_ctx)
264989410cdSAndrii Nakryiko {
265989410cdSAndrii Nakryiko 	return 0;
266989410cdSAndrii Nakryiko }
267989410cdSAndrii Nakryiko 
268989410cdSAndrii Nakryiko SEC("?perf_event")
269989410cdSAndrii Nakryiko __success __log_level(2)
270989410cdSAndrii Nakryiko int arg_tag_ctx_perf(void *ctx)
271989410cdSAndrii Nakryiko {
272989410cdSAndrii Nakryiko 	return subprog_ctx_tag(ctx) +
273989410cdSAndrii Nakryiko 	       perf_subprog_regs(ctx) +
274989410cdSAndrii Nakryiko 	       perf_subprog_typedef(ctx) +
275989410cdSAndrii Nakryiko 	       perf_subprog_canonical(ctx);
276989410cdSAndrii Nakryiko }
277989410cdSAndrii Nakryiko 
278989410cdSAndrii Nakryiko __weak int iter_subprog_void(void *ctx __arg_ctx)
279989410cdSAndrii Nakryiko {
280989410cdSAndrii Nakryiko 	return 0;
281989410cdSAndrii Nakryiko }
282989410cdSAndrii Nakryiko 
283989410cdSAndrii Nakryiko __weak int iter_subprog_typed(struct bpf_iter__task *ctx __arg_ctx)
284989410cdSAndrii Nakryiko {
285989410cdSAndrii Nakryiko 	return 0;
286989410cdSAndrii Nakryiko }
287989410cdSAndrii Nakryiko 
288989410cdSAndrii Nakryiko SEC("?iter/task")
289989410cdSAndrii Nakryiko __success __log_level(2)
290989410cdSAndrii Nakryiko int arg_tag_ctx_iter_task(struct bpf_iter__task *ctx)
291989410cdSAndrii Nakryiko {
292989410cdSAndrii Nakryiko 	return (iter_subprog_void(ctx) + iter_subprog_typed(ctx)) & 1;
293989410cdSAndrii Nakryiko }
294989410cdSAndrii Nakryiko 
295989410cdSAndrii Nakryiko __weak int tracing_subprog_void(void *ctx __arg_ctx)
296989410cdSAndrii Nakryiko {
297989410cdSAndrii Nakryiko 	return 0;
298989410cdSAndrii Nakryiko }
299989410cdSAndrii Nakryiko 
300989410cdSAndrii Nakryiko __weak int tracing_subprog_u64(u64 *ctx __arg_ctx)
301989410cdSAndrii Nakryiko {
302989410cdSAndrii Nakryiko 	return 0;
303989410cdSAndrii Nakryiko }
304989410cdSAndrii Nakryiko 
305989410cdSAndrii Nakryiko int acc;
306989410cdSAndrii Nakryiko 
307989410cdSAndrii Nakryiko SEC("?fentry/" SYS_PREFIX "sys_nanosleep")
308989410cdSAndrii Nakryiko __success __log_level(2)
309989410cdSAndrii Nakryiko int BPF_PROG(arg_tag_ctx_fentry)
310989410cdSAndrii Nakryiko {
311989410cdSAndrii Nakryiko 	acc += tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
312989410cdSAndrii Nakryiko 	return 0;
313989410cdSAndrii Nakryiko }
314989410cdSAndrii Nakryiko 
315989410cdSAndrii Nakryiko SEC("?fexit/" SYS_PREFIX "sys_nanosleep")
316989410cdSAndrii Nakryiko __success __log_level(2)
317989410cdSAndrii Nakryiko int BPF_PROG(arg_tag_ctx_fexit)
318989410cdSAndrii Nakryiko {
319989410cdSAndrii Nakryiko 	acc += tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
320989410cdSAndrii Nakryiko 	return 0;
321989410cdSAndrii Nakryiko }
322989410cdSAndrii Nakryiko 
323989410cdSAndrii Nakryiko SEC("?fmod_ret/" SYS_PREFIX "sys_nanosleep")
324989410cdSAndrii Nakryiko __success __log_level(2)
325989410cdSAndrii Nakryiko int BPF_PROG(arg_tag_ctx_fmod_ret)
326989410cdSAndrii Nakryiko {
327989410cdSAndrii Nakryiko 	return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
328989410cdSAndrii Nakryiko }
329989410cdSAndrii Nakryiko 
330989410cdSAndrii Nakryiko SEC("?lsm/bpf")
331989410cdSAndrii Nakryiko __success __log_level(2)
332989410cdSAndrii Nakryiko int BPF_PROG(arg_tag_ctx_lsm)
333989410cdSAndrii Nakryiko {
334989410cdSAndrii Nakryiko 	return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
335989410cdSAndrii Nakryiko }
336989410cdSAndrii Nakryiko 
337989410cdSAndrii Nakryiko SEC("?struct_ops/test_1")
338989410cdSAndrii Nakryiko __success __log_level(2)
339989410cdSAndrii Nakryiko int BPF_PROG(arg_tag_ctx_struct_ops)
340989410cdSAndrii Nakryiko {
341989410cdSAndrii Nakryiko 	return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx);
342989410cdSAndrii Nakryiko }
343989410cdSAndrii Nakryiko 
344989410cdSAndrii Nakryiko SEC(".struct_ops")
345989410cdSAndrii Nakryiko struct bpf_dummy_ops dummy_1 = {
346989410cdSAndrii Nakryiko 	.test_1 = (void *)arg_tag_ctx_struct_ops,
347989410cdSAndrii Nakryiko };
348989410cdSAndrii Nakryiko 
349989410cdSAndrii Nakryiko SEC("?syscall")
350989410cdSAndrii Nakryiko __success __log_level(2)
351989410cdSAndrii Nakryiko int arg_tag_ctx_syscall(void *ctx)
352989410cdSAndrii Nakryiko {
353989410cdSAndrii Nakryiko 	return tracing_subprog_void(ctx) + tracing_subprog_u64(ctx) + tp_whatever(ctx);
3540a0ffcacSAndrii Nakryiko }
3550a0ffcacSAndrii Nakryiko 
3560a0ffcacSAndrii Nakryiko __weak int subprog_dynptr(struct bpf_dynptr *dptr)
3570a0ffcacSAndrii Nakryiko {
3580a0ffcacSAndrii Nakryiko 	long *d, t, buf[1] = {};
3590a0ffcacSAndrii Nakryiko 
3600a0ffcacSAndrii Nakryiko 	d = bpf_dynptr_data(dptr, 0, sizeof(long));
3610a0ffcacSAndrii Nakryiko 	if (!d)
3620a0ffcacSAndrii Nakryiko 		return 0;
3630a0ffcacSAndrii Nakryiko 
3640a0ffcacSAndrii Nakryiko 	t = *d + 1;
3650a0ffcacSAndrii Nakryiko 
3660a0ffcacSAndrii Nakryiko 	d = bpf_dynptr_slice(dptr, 0, &buf, sizeof(long));
3670a0ffcacSAndrii Nakryiko 	if (!d)
3680a0ffcacSAndrii Nakryiko 		return t;
3690a0ffcacSAndrii Nakryiko 
3700a0ffcacSAndrii Nakryiko 	t = *d + 2;
3710a0ffcacSAndrii Nakryiko 
3720a0ffcacSAndrii Nakryiko 	return t;
3730a0ffcacSAndrii Nakryiko }
3740a0ffcacSAndrii Nakryiko 
3750a0ffcacSAndrii Nakryiko SEC("?xdp")
3760a0ffcacSAndrii Nakryiko __success __log_level(2)
3770a0ffcacSAndrii Nakryiko int arg_tag_dynptr(struct xdp_md *ctx)
3780a0ffcacSAndrii Nakryiko {
3790a0ffcacSAndrii Nakryiko 	struct bpf_dynptr dptr;
3800a0ffcacSAndrii Nakryiko 
3810a0ffcacSAndrii Nakryiko 	bpf_dynptr_from_xdp(ctx, 0, &dptr);
3820a0ffcacSAndrii Nakryiko 
3830a0ffcacSAndrii Nakryiko 	return subprog_dynptr(&dptr);
3840a0ffcacSAndrii Nakryiko }
3850a0ffcacSAndrii Nakryiko 
386e8a339b5SAndrii Nakryiko char _license[] SEC("license") = "GPL";
387