1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/bpf.h>
3 #include <bpf/bpf_helpers.h>
4 #include "bpf_misc.h"
5 #include "bpf_test_utils.h"
6
7 int classifier_0(struct __sk_buff *skb);
8
9 struct {
10 __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
11 __uint(max_entries, 1);
12 __uint(key_size, sizeof(__u32));
13 __array(values, void (void));
14 } jmp_table SEC(".maps") = {
15 .values = {
16 [0] = (void *) &classifier_0,
17 },
18 };
19
20 __auxiliary
21 SEC("tc")
classifier_0(struct __sk_buff * skb)22 int classifier_0(struct __sk_buff *skb)
23 {
24 return 0;
25 }
26
27 static __noinline
subprog_tail0(struct __sk_buff * skb)28 int subprog_tail0(struct __sk_buff *skb)
29 {
30 int ret = 0;
31
32 bpf_tail_call_static(skb, &jmp_table, 0);
33 barrier_var(ret);
34 return ret;
35 }
36
37 static __noinline
callback_loop(int index,void ** cb_ctx)38 int callback_loop(int index, void **cb_ctx)
39 {
40 int ret;
41
42 ret = subprog_tail0(*cb_ctx);
43 barrier_var(ret);
44 return ret ? 1 : 0;
45 }
46
47 static __noinline
callback_tail(int index,void ** cb_ctx)48 int callback_tail(int index, void **cb_ctx)
49 {
50 bpf_tail_call_static(*cb_ctx, &jmp_table, 0);
51 return 0;
52 }
53
54 static __noinline
callback_empty(int index,void * data)55 int callback_empty(int index, void *data)
56 {
57 return 0;
58 }
59
60 /* callback involving subprog with tail call is rejected */
61 SEC("tc")
62 __failure __msg("cannot tail call within callback")
tailcall_callback_1(struct __sk_buff * skb)63 int tailcall_callback_1(struct __sk_buff *skb)
64 {
65 clobber_regs_stack();
66
67 bpf_loop(1, callback_loop, &skb, 0);
68 return 0;
69 }
70
71 /* subprogs with tailcall do not affect no-tailcall callback */
72 SEC("tc")
73 __success
74 __retval(0)
tailcall_callback_2(struct __sk_buff * skb)75 int tailcall_callback_2(struct __sk_buff *skb)
76 {
77 int ret;
78
79 clobber_regs_stack();
80
81 ret = subprog_tail0(skb);
82 __sink(ret);
83
84 bpf_loop(1, callback_empty, NULL, 0);
85 return 0;
86 }
87
88 /* callback with a direct tail call is rejected without a verifier bug */
89 SEC("tc")
90 __failure __msg("cannot tail call within callback")
tailcall_callback_3(struct __sk_buff * skb)91 int tailcall_callback_3(struct __sk_buff *skb)
92 {
93 bpf_loop(1, callback_tail, &skb, 0);
94 return 0;
95 }
96
97 char __license[] SEC("license") = "GPL";
98