xref: /linux/tools/testing/selftests/bpf/progs/verifier_cfg.c (revision 917cfd1ed5ed295a0ad3df5deb72d2ae9c796dbd)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Converted from tools/testing/selftests/bpf/verifier/cfg.c */
3 
4 #include <linux/bpf.h>
5 #include <bpf/bpf_helpers.h>
6 #include "../../../include/linux/filter.h"
7 #include "bpf_misc.h"
8 
9 SEC("socket")
10 __description("unreachable")
11 __failure __msg("unreachable")
12 __failure_unpriv
13 __naked void unreachable(void)
14 {
15 	asm volatile ("					\
16 	exit;						\
17 	exit;						\
18 "	::: __clobber_all);
19 }
20 
21 SEC("socket")
22 __description("unreachable2")
23 __failure __msg("unreachable")
24 __failure_unpriv
25 __naked void unreachable2(void)
26 {
27 	asm volatile ("					\
28 	goto l0_%=;					\
29 	goto l0_%=;					\
30 l0_%=:	exit;						\
31 "	::: __clobber_all);
32 }
33 
34 SEC("socket")
35 __description("out of range jump")
36 __failure __msg("jump out of range")
37 __failure_unpriv
38 __naked void out_of_range_jump(void)
39 {
40 	asm volatile ("					\
41 	goto l0_%=;					\
42 	exit;						\
43 l0_%=:							\
44 "	::: __clobber_all);
45 }
46 
47 SEC("socket")
48 __description("out of range jump2")
49 __failure __msg("jump out of range")
50 __failure_unpriv
51 __naked void out_of_range_jump2(void)
52 {
53 	asm volatile ("					\
54 	goto -2;					\
55 	exit;						\
56 "	::: __clobber_all);
57 }
58 
59 static __naked __noinline __used int cross_subprog_target(void)
60 {
61 	asm volatile ("					\
62 	r0 = 0;						\
63 	exit;						\
64 "	::: __clobber_all);
65 }
66 
67 SEC("socket")
68 __description("jump across subprogram boundary")
69 __failure __msg("jump out of range from insn 1")
70 __msg("jump_across_subprog_boundary @ verifier_cfg.c")
71 __naked void jump_across_subprog_boundary(void)
72 {
73 	asm volatile ("					\
74 	call cross_subprog_target;			\
75 	goto +1;					\
76 	exit;						\
77 "	::: __clobber_all);
78 }
79 
80 static __naked __noinline __used int fallthrough_subprog(void)
81 {
82 	asm volatile ("					\
83 	r0 = 0;						\
84 "	::: __clobber_all);
85 }
86 
87 SEC("socket")
88 __description("subprogram fallthrough")
89 __failure __msg("last insn is not an exit or jmp")
90 __msg("fallthrough_subprog @ verifier_cfg.c")
91 __naked void subprog_fallthrough(void)
92 {
93 	asm volatile ("					\
94 	call fallthrough_subprog;			\
95 	exit;						\
96 "	::: __clobber_all);
97 }
98 
99 SEC("socket")
100 __description("invalid DW LDSX instruction in diagnostics")
101 __failure __msg("BUG_ldx_99")
102 __log_level(2)
103 __naked void invalid_dw_ldsx(void)
104 {
105 	asm volatile ("					\
106 	.8byte %[ldsx_dw];				\
107 "	:
108 	: __imm_insn(ldsx_dw, BPF_RAW_INSN(BPF_LDX | BPF_MEMSX | BPF_DW, BPF_REG_0, BPF_REG_0, 0, 0))
109 	: __clobber_all);
110 }
111 
112 SEC("socket")
113 __description("loop (back-edge)")
114 __failure __msg("unreachable insn 1")
115 __msg_unpriv("back-edge")
116 __naked void loop_back_edge(void)
117 {
118 	asm volatile ("					\
119 l0_%=:	goto l0_%=;					\
120 	exit;						\
121 "	::: __clobber_all);
122 }
123 
124 SEC("socket")
125 __description("loop2 (back-edge)")
126 __failure __msg("unreachable insn 4")
127 __msg_unpriv("back-edge")
128 __naked void loop2_back_edge(void)
129 {
130 	asm volatile ("					\
131 l0_%=:	r1 = r0;					\
132 	r2 = r0;					\
133 	r3 = r0;					\
134 	goto l0_%=;					\
135 	exit;						\
136 "	::: __clobber_all);
137 }
138 
139 SEC("socket")
140 __description("conditional loop")
141 __failure __msg("infinite loop detected")
142 __msg_unpriv("back-edge")
143 __naked void conditional_loop(void)
144 {
145 	asm volatile ("					\
146 	r0 = r1;					\
147 l0_%=:	r2 = r0;					\
148 	r3 = r0;					\
149 	if r1 == 0 goto l0_%=;				\
150 	exit;						\
151 "	::: __clobber_all);
152 }
153 
154 SEC("socket")
155 __description("conditional loop (2)")
156 __success
157 __failure_unpriv __msg_unpriv("back-edge from insn 10 to 11")
158 __naked void conditional_loop2(void)
159 {
160 	asm volatile ("					\
161 	r9 = 2 ll;					\
162 	r3 = 0x20 ll;					\
163 	r4 = 0x35 ll;					\
164 	r8 = r4;					\
165 	goto l1_%=;					\
166 l0_%=:	r9 -= r3;					\
167 	r9 -= r4;					\
168 	r9 -= r8;					\
169 l1_%=:	r8 += r4;					\
170 	if r8 < 0x64 goto l0_%=;			\
171 	r0 = r9;					\
172 	exit;						\
173 "	::: __clobber_all);
174 }
175 
176 SEC("socket")
177 __description("unconditional loop after conditional jump")
178 __failure __msg("infinite loop detected")
179 __failure_unpriv __msg_unpriv("back-edge from insn 3 to 2")
180 __naked void uncond_loop_after_cond_jmp(void)
181 {
182 	asm volatile ("					\
183 	r0 = 0;						\
184 	if r0 > 0 goto l1_%=;				\
185 l0_%=:	r0 = 1;						\
186 	goto l0_%=;					\
187 l1_%=:	exit;						\
188 "	::: __clobber_all);
189 }
190 
191 
192 __naked __noinline __used
193 static unsigned long never_ending_subprog()
194 {
195 	asm volatile ("					\
196 	r0 = r1;					\
197 	goto -1;					\
198 "	::: __clobber_all);
199 }
200 
201 SEC("socket")
202 __description("unconditional loop after conditional jump")
203 /* infinite loop is detected *after* check_cfg() */
204 __failure __msg("infinite loop detected")
205 __naked void uncond_loop_in_subprog_after_cond_jmp(void)
206 {
207 	asm volatile ("					\
208 	r0 = 0;						\
209 	if r0 > 0 goto l1_%=;				\
210 l0_%=:	r0 += 1;					\
211 	call never_ending_subprog;			\
212 l1_%=:	exit;						\
213 "	::: __clobber_all);
214 }
215 
216 struct {
217 	__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
218 	__uint(max_entries, 1);
219 	__type(key, __u32);
220 	__type(value, __u32);
221 } map_array SEC(".maps");
222 
223 extern void bpf_throw(__u64 cookie) __ksym;
224 
225 /*
226  * The subprogram leaves through the tail call or the exception and never
227  * reaches an exit insn, so the hidden edge of the tail call has no exit to
228  * point at. The stack access makes the liveness pass walk the subprogram,
229  * and the loop compiles to a single jump back onto itself.
230  */
231 __noinline __used
232 static int tail_call_or_throw_subprog(void *ctx)
233 {
234 	volatile __u32 idx = 0;
235 
236 	bpf_tail_call(ctx, &map_array, idx);
237 	bpf_throw(0);
238 	for (;;) {}
239 	return 0;
240 }
241 
242 SEC("tc")
243 __description("tail call in a subprogram without an exit")
244 __arch_x86_64
245 __arch_arm64
246 __success
247 __naked void tail_call_in_subprog_without_exit(void)
248 {
249 	asm volatile ("					\
250 	call tail_call_or_throw_subprog;		\
251 	exit;						\
252 "	::: __clobber_all);
253 }
254 
255 char _license[] SEC("license") = "GPL";
256