xref: /linux/tools/testing/selftests/bpf/prog_tests/exceptions.c (revision e2683c8868d03382da7e1ce8453b543a043066d1)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include <network_helpers.h>
4 
5 #include "exceptions.skel.h"
6 #include "exceptions_ext.skel.h"
7 #include "exceptions_fail.skel.h"
8 #include "exceptions_assert.skel.h"
9 
10 static char log_buf[1024 * 1024];
11 
12 static void test_exceptions_failure(void)
13 {
14 	RUN_TESTS(exceptions_fail);
15 }
16 
17 static void test_exceptions_success(void)
18 {
19 	LIBBPF_OPTS(bpf_test_run_opts, ropts,
20 		.data_in = &pkt_v4,
21 		.data_size_in = sizeof(pkt_v4),
22 		.repeat = 1,
23 	);
24 	struct exceptions_ext *eskel = NULL;
25 	struct exceptions *skel;
26 	int ret;
27 
28 	skel = exceptions__open();
29 	if (!ASSERT_OK_PTR(skel, "exceptions__open"))
30 		return;
31 
32 	ret = exceptions__load(skel);
33 	if (!ASSERT_OK(ret, "exceptions__load"))
34 		goto done;
35 
36 	if (!ASSERT_OK(bpf_map_update_elem(bpf_map__fd(skel->maps.jmp_table), &(int){0},
37 					   &(int){bpf_program__fd(skel->progs.exception_tail_call_target)}, BPF_ANY),
38 		       "bpf_map_update_elem jmp_table"))
39 		goto done;
40 
41 #define RUN_SUCCESS(_prog, return_val)						  \
42 	if (!test__start_subtest(#_prog)) goto _prog##_##return_val;		  \
43 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs._prog), &ropts); \
44 	ASSERT_OK(ret, #_prog " prog run ret");					  \
45 	ASSERT_EQ(ropts.retval, return_val, #_prog " prog run retval");		  \
46 	_prog##_##return_val:
47 
48 	RUN_SUCCESS(exception_throw_always_1, 64);
49 	RUN_SUCCESS(exception_throw_always_2, 32);
50 	RUN_SUCCESS(exception_throw_unwind_1, 16);
51 	RUN_SUCCESS(exception_throw_unwind_2, 32);
52 	RUN_SUCCESS(exception_throw_default, 0);
53 	RUN_SUCCESS(exception_throw_default_value, 5);
54 	RUN_SUCCESS(exception_tail_call, 24);
55 	RUN_SUCCESS(exception_ext, 0);
56 	RUN_SUCCESS(exception_ext_mod_cb_runtime, 35);
57 	RUN_SUCCESS(exception_throw_subprog, 1);
58 	RUN_SUCCESS(exception_assert_nz_gfunc, 1);
59 	RUN_SUCCESS(exception_assert_zero_gfunc, 1);
60 	RUN_SUCCESS(exception_assert_neg_gfunc, 1);
61 	RUN_SUCCESS(exception_assert_pos_gfunc, 1);
62 	RUN_SUCCESS(exception_assert_negeq_gfunc, 1);
63 	RUN_SUCCESS(exception_assert_poseq_gfunc, 1);
64 	RUN_SUCCESS(exception_assert_nz_gfunc_with, 1);
65 	RUN_SUCCESS(exception_assert_zero_gfunc_with, 1);
66 	RUN_SUCCESS(exception_assert_neg_gfunc_with, 1);
67 	RUN_SUCCESS(exception_assert_pos_gfunc_with, 1);
68 	RUN_SUCCESS(exception_assert_negeq_gfunc_with, 1);
69 	RUN_SUCCESS(exception_assert_poseq_gfunc_with, 1);
70 	RUN_SUCCESS(exception_bad_assert_nz_gfunc, 0);
71 	RUN_SUCCESS(exception_bad_assert_zero_gfunc, 0);
72 	RUN_SUCCESS(exception_bad_assert_neg_gfunc, 0);
73 	RUN_SUCCESS(exception_bad_assert_pos_gfunc, 0);
74 	RUN_SUCCESS(exception_bad_assert_negeq_gfunc, 0);
75 	RUN_SUCCESS(exception_bad_assert_poseq_gfunc, 0);
76 	RUN_SUCCESS(exception_bad_assert_nz_gfunc_with, 100);
77 	RUN_SUCCESS(exception_bad_assert_zero_gfunc_with, 105);
78 	RUN_SUCCESS(exception_bad_assert_neg_gfunc_with, 200);
79 	RUN_SUCCESS(exception_bad_assert_pos_gfunc_with, 0);
80 	RUN_SUCCESS(exception_bad_assert_negeq_gfunc_with, 101);
81 	RUN_SUCCESS(exception_bad_assert_poseq_gfunc_with, 99);
82 	RUN_SUCCESS(exception_assert_range, 1);
83 	RUN_SUCCESS(exception_assert_range_with, 1);
84 	RUN_SUCCESS(exception_bad_assert_range, 0);
85 	RUN_SUCCESS(exception_bad_assert_range_with, 10);
86 	RUN_SUCCESS(exception_throw_from_void_global, 11);
87 
88 #define RUN_EXT(load_ret, attach_err, expr, msg, after_link)			  \
89 	{									  \
90 		LIBBPF_OPTS(bpf_object_open_opts, o, .kernel_log_buf = log_buf,		 \
91 						     .kernel_log_size = sizeof(log_buf), \
92 						     .kernel_log_level = 2);		 \
93 		exceptions_ext__destroy(eskel);					  \
94 		eskel = exceptions_ext__open_opts(&o);				  \
95 		struct bpf_program *prog = NULL;				  \
96 		struct bpf_link *link = NULL;					  \
97 		if (!ASSERT_OK_PTR(eskel, "exceptions_ext__open"))		  \
98 			goto done;						  \
99 		(expr);								  \
100 		ASSERT_OK_PTR(bpf_program__name(prog), bpf_program__name(prog));  \
101 		if (!ASSERT_EQ(exceptions_ext__load(eskel), load_ret,		  \
102 			       "exceptions_ext__load"))	{			  \
103 			printf("%s\n", log_buf);				  \
104 			goto done;						  \
105 		}								  \
106 		if (load_ret != 0) {						  \
107 			if (!ASSERT_OK_PTR(strstr(log_buf, msg), "strstr")) {	  \
108 				printf("%s\n", log_buf);			  \
109 				goto done;					  \
110 			}							  \
111 		}								  \
112 		if (!load_ret && attach_err) {					  \
113 			if (!ASSERT_ERR_PTR(link = bpf_program__attach(prog), "attach err")) \
114 				goto done;					  \
115 		} else if (!load_ret) {						  \
116 			if (!ASSERT_OK_PTR(link = bpf_program__attach(prog), "attach ok"))  \
117 				goto done;					  \
118 			(void)(after_link);					  \
119 			bpf_link__destroy(link);				  \
120 		}								  \
121 	}
122 
123 	if (test__start_subtest("non-throwing fentry -> exception_cb"))
124 		RUN_EXT(-EINVAL, true, ({
125 			prog = eskel->progs.pfentry;
126 			bpf_program__set_autoload(prog, true);
127 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
128 				       bpf_program__fd(skel->progs.exception_ext_mod_cb_runtime),
129 				       "exception_cb_mod"), "set_attach_target"))
130 				goto done;
131 		}), "Tracing programs cannot attach to exception callback", 0);
132 
133 	if (test__start_subtest("throwing fentry -> exception_cb"))
134 		RUN_EXT(-EINVAL, true, ({
135 			prog = eskel->progs.throwing_fentry;
136 			bpf_program__set_autoload(prog, true);
137 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
138 				       bpf_program__fd(skel->progs.exception_ext_mod_cb_runtime),
139 				       "exception_cb_mod"), "set_attach_target"))
140 				goto done;
141 		}), "Tracing programs cannot attach to exception callback", 0);
142 
143 	if (test__start_subtest("non-throwing fexit -> exception_cb"))
144 		RUN_EXT(-EINVAL, true, ({
145 			prog = eskel->progs.pfexit;
146 			bpf_program__set_autoload(prog, true);
147 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
148 				       bpf_program__fd(skel->progs.exception_ext_mod_cb_runtime),
149 				       "exception_cb_mod"), "set_attach_target"))
150 				goto done;
151 		}), "Tracing programs cannot attach to exception callback", 0);
152 
153 	if (test__start_subtest("throwing fexit -> exception_cb"))
154 		RUN_EXT(-EINVAL, true, ({
155 			prog = eskel->progs.throwing_fexit;
156 			bpf_program__set_autoload(prog, true);
157 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
158 				       bpf_program__fd(skel->progs.exception_ext_mod_cb_runtime),
159 				       "exception_cb_mod"), "set_attach_target"))
160 				goto done;
161 		}), "Tracing programs cannot attach to exception callback", 0);
162 
163 	if (test__start_subtest("throwing extension (with custom cb) -> exception_cb"))
164 		RUN_EXT(-EINVAL, true, ({
165 			prog = eskel->progs.throwing_exception_cb_extension;
166 			bpf_program__set_autoload(prog, true);
167 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
168 				       bpf_program__fd(skel->progs.exception_ext_mod_cb_runtime),
169 				       "exception_cb_mod"), "set_attach_target"))
170 				goto done;
171 		}), "Extension programs cannot attach to exception callback", 0);
172 
173 	if (test__start_subtest("throwing extension -> global func in exception_cb"))
174 		RUN_EXT(0, false, ({
175 			prog = eskel->progs.throwing_exception_cb_extension;
176 			bpf_program__set_autoload(prog, true);
177 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
178 				       bpf_program__fd(skel->progs.exception_ext_mod_cb_runtime),
179 				       "exception_cb_mod_global"), "set_attach_target"))
180 				goto done;
181 		}), "", ({ RUN_SUCCESS(exception_ext_mod_cb_runtime, 131); }));
182 
183 	if (test__start_subtest("throwing extension (with custom cb) -> global func in exception_cb"))
184 		RUN_EXT(0, false, ({
185 			prog = eskel->progs.throwing_extension;
186 			bpf_program__set_autoload(prog, true);
187 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
188 				       bpf_program__fd(skel->progs.exception_ext),
189 				       "exception_ext_global"), "set_attach_target"))
190 				goto done;
191 		}), "", ({ RUN_SUCCESS(exception_ext, 128); }));
192 
193 	if (test__start_subtest("non-throwing fentry -> non-throwing subprog"))
194 		/* non-throwing fentry -> non-throwing subprog : OK */
195 		RUN_EXT(0, false, ({
196 			prog = eskel->progs.pfentry;
197 			bpf_program__set_autoload(prog, true);
198 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
199 				       bpf_program__fd(skel->progs.exception_throw_subprog),
200 				       "subprog"), "set_attach_target"))
201 				goto done;
202 		}), "", 0);
203 
204 	if (test__start_subtest("throwing fentry -> non-throwing subprog"))
205 		/* throwing fentry -> non-throwing subprog : OK */
206 		RUN_EXT(0, false, ({
207 			prog = eskel->progs.throwing_fentry;
208 			bpf_program__set_autoload(prog, true);
209 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
210 				       bpf_program__fd(skel->progs.exception_throw_subprog),
211 				       "subprog"), "set_attach_target"))
212 				goto done;
213 		}), "", 0);
214 
215 	if (test__start_subtest("non-throwing fentry -> throwing subprog"))
216 		/* non-throwing fentry -> throwing subprog : OK */
217 		RUN_EXT(0, false, ({
218 			prog = eskel->progs.pfentry;
219 			bpf_program__set_autoload(prog, true);
220 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
221 				       bpf_program__fd(skel->progs.exception_throw_subprog),
222 				       "throwing_subprog"), "set_attach_target"))
223 				goto done;
224 		}), "", 0);
225 
226 	if (test__start_subtest("throwing fentry -> throwing subprog"))
227 		/* throwing fentry -> throwing subprog : OK */
228 		RUN_EXT(0, false, ({
229 			prog = eskel->progs.throwing_fentry;
230 			bpf_program__set_autoload(prog, true);
231 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
232 				       bpf_program__fd(skel->progs.exception_throw_subprog),
233 				       "throwing_subprog"), "set_attach_target"))
234 				goto done;
235 		}), "", 0);
236 
237 	if (test__start_subtest("non-throwing fexit -> non-throwing subprog"))
238 		/* non-throwing fexit -> non-throwing subprog : OK */
239 		RUN_EXT(0, false, ({
240 			prog = eskel->progs.pfexit;
241 			bpf_program__set_autoload(prog, true);
242 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
243 				       bpf_program__fd(skel->progs.exception_throw_subprog),
244 				       "subprog"), "set_attach_target"))
245 				goto done;
246 		}), "", 0);
247 
248 	if (test__start_subtest("throwing fexit -> non-throwing subprog"))
249 		/* throwing fexit -> non-throwing subprog : OK */
250 		RUN_EXT(0, false, ({
251 			prog = eskel->progs.throwing_fexit;
252 			bpf_program__set_autoload(prog, true);
253 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
254 				       bpf_program__fd(skel->progs.exception_throw_subprog),
255 				       "subprog"), "set_attach_target"))
256 				goto done;
257 		}), "", 0);
258 
259 	if (test__start_subtest("non-throwing fexit -> throwing subprog"))
260 		/* non-throwing fexit -> throwing subprog : OK */
261 		RUN_EXT(0, false, ({
262 			prog = eskel->progs.pfexit;
263 			bpf_program__set_autoload(prog, true);
264 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
265 				       bpf_program__fd(skel->progs.exception_throw_subprog),
266 				       "throwing_subprog"), "set_attach_target"))
267 				goto done;
268 		}), "", 0);
269 
270 	if (test__start_subtest("throwing fexit -> throwing subprog"))
271 		/* throwing fexit -> throwing subprog : OK */
272 		RUN_EXT(0, false, ({
273 			prog = eskel->progs.throwing_fexit;
274 			bpf_program__set_autoload(prog, true);
275 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
276 				       bpf_program__fd(skel->progs.exception_throw_subprog),
277 				       "throwing_subprog"), "set_attach_target"))
278 				goto done;
279 		}), "", 0);
280 
281 	/* fmod_ret not allowed for subprog - Check so we remember to handle its
282 	 * throwing specification compatibility with target when supported.
283 	 */
284 	if (test__start_subtest("non-throwing fmod_ret -> non-throwing subprog"))
285 		RUN_EXT(-EINVAL, true, ({
286 			prog = eskel->progs.pfmod_ret;
287 			bpf_program__set_autoload(prog, true);
288 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
289 				       bpf_program__fd(skel->progs.exception_throw_subprog),
290 				       "subprog"), "set_attach_target"))
291 				goto done;
292 		}), "can't modify return codes of BPF program", 0);
293 
294 	/* fmod_ret not allowed for subprog - Check so we remember to handle its
295 	 * throwing specification compatibility with target when supported.
296 	 */
297 	if (test__start_subtest("non-throwing fmod_ret -> non-throwing global subprog"))
298 		RUN_EXT(-EINVAL, true, ({
299 			prog = eskel->progs.pfmod_ret;
300 			bpf_program__set_autoload(prog, true);
301 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
302 				       bpf_program__fd(skel->progs.exception_throw_subprog),
303 				       "global_subprog"), "set_attach_target"))
304 				goto done;
305 		}), "can't modify return codes of BPF program", 0);
306 
307 	if (test__start_subtest("non-throwing extension -> non-throwing subprog"))
308 		/* non-throwing extension -> non-throwing subprog : BAD (!global) */
309 		RUN_EXT(-EINVAL, true, ({
310 			prog = eskel->progs.extension;
311 			bpf_program__set_autoload(prog, true);
312 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
313 				       bpf_program__fd(skel->progs.exception_throw_subprog),
314 				       "subprog"), "set_attach_target"))
315 				goto done;
316 		}), "subprog() is not a global function", 0);
317 
318 	if (test__start_subtest("non-throwing extension -> throwing subprog"))
319 		/* non-throwing extension -> throwing subprog : BAD (!global) */
320 		RUN_EXT(-EINVAL, true, ({
321 			prog = eskel->progs.extension;
322 			bpf_program__set_autoload(prog, true);
323 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
324 				       bpf_program__fd(skel->progs.exception_throw_subprog),
325 				       "throwing_subprog"), "set_attach_target"))
326 				goto done;
327 		}), "throwing_subprog() is not a global function", 0);
328 
329 	if (test__start_subtest("non-throwing extension -> non-throwing subprog"))
330 		/* non-throwing extension -> non-throwing global subprog : OK */
331 		RUN_EXT(0, false, ({
332 			prog = eskel->progs.extension;
333 			bpf_program__set_autoload(prog, true);
334 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
335 				       bpf_program__fd(skel->progs.exception_throw_subprog),
336 				       "global_subprog"), "set_attach_target"))
337 				goto done;
338 		}), "", 0);
339 
340 	if (test__start_subtest("non-throwing extension -> throwing global subprog"))
341 		/* non-throwing extension -> throwing global subprog : OK */
342 		RUN_EXT(0, false, ({
343 			prog = eskel->progs.extension;
344 			bpf_program__set_autoload(prog, true);
345 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
346 				       bpf_program__fd(skel->progs.exception_throw_subprog),
347 				       "throwing_global_subprog"), "set_attach_target"))
348 				goto done;
349 		}), "", 0);
350 
351 	if (test__start_subtest("throwing extension -> throwing global subprog"))
352 		/* throwing extension -> throwing global subprog : OK */
353 		RUN_EXT(0, false, ({
354 			prog = eskel->progs.throwing_extension;
355 			bpf_program__set_autoload(prog, true);
356 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
357 				       bpf_program__fd(skel->progs.exception_throw_subprog),
358 				       "throwing_global_subprog"), "set_attach_target"))
359 				goto done;
360 		}), "", 0);
361 
362 	if (test__start_subtest("throwing extension -> non-throwing global subprog"))
363 		/* throwing extension -> non-throwing global subprog : OK */
364 		RUN_EXT(0, false, ({
365 			prog = eskel->progs.throwing_extension;
366 			bpf_program__set_autoload(prog, true);
367 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
368 				       bpf_program__fd(skel->progs.exception_throw_subprog),
369 				       "global_subprog"), "set_attach_target"))
370 				goto done;
371 		}), "", 0);
372 
373 	if (test__start_subtest("non-throwing extension -> main subprog"))
374 		/* non-throwing extension -> main subprog : OK */
375 		RUN_EXT(0, false, ({
376 			prog = eskel->progs.extension;
377 			bpf_program__set_autoload(prog, true);
378 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
379 				       bpf_program__fd(skel->progs.exception_throw_subprog),
380 				       "exception_throw_subprog"), "set_attach_target"))
381 				goto done;
382 		}), "", 0);
383 
384 	if (test__start_subtest("throwing extension -> main subprog"))
385 		/* throwing extension -> main subprog : OK */
386 		RUN_EXT(0, false, ({
387 			prog = eskel->progs.throwing_extension;
388 			bpf_program__set_autoload(prog, true);
389 			if (!ASSERT_OK(bpf_program__set_attach_target(prog,
390 				       bpf_program__fd(skel->progs.exception_throw_subprog),
391 				       "exception_throw_subprog"), "set_attach_target"))
392 				goto done;
393 		}), "", 0);
394 
395 done:
396 	exceptions_ext__destroy(eskel);
397 	exceptions__destroy(skel);
398 }
399 
400 static void test_exceptions_assertions(void)
401 {
402 	RUN_TESTS(exceptions_assert);
403 }
404 
405 void test_exceptions(void)
406 {
407 	test_exceptions_success();
408 	test_exceptions_failure();
409 	test_exceptions_assertions();
410 }
411