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