1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include <network_helpers.h>
5 #include "exceptions.skel.h"
6 #include "exceptions_ext.skel.h"
7 #include "exceptions_fail.skel.h"
8 #include "exceptions_assert.skel.h"
10 static char log_buf[1024 * 1024];
12 static void test_exceptions_failure(void)
14 RUN_TESTS(exceptions_fail);
17 static void test_exceptions_success(void)
19 LIBBPF_OPTS(bpf_test_run_opts, ropts,
21 .data_size_in = sizeof(pkt_v4),
24 struct exceptions_ext *eskel = NULL;
25 struct exceptions *skel;
28 skel = exceptions__open();
29 if (!ASSERT_OK_PTR(skel, "exceptions__open"))
32 ret = exceptions__load(skel);
33 if (!ASSERT_OK(ret, "exceptions__load"))
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"))
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"); \
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);
87 #define RUN_EXT(load_ret, attach_err, expr, msg, after_link) \
89 LIBBPF_OPTS(bpf_object_open_opts, o, .kernel_log_buf = log_buf, \
90 .kernel_log_size = sizeof(log_buf), \
91 .kernel_log_level = 2); \
92 exceptions_ext__destroy(eskel); \
93 eskel = exceptions_ext__open_opts(&o); \
94 struct bpf_program *prog = NULL; \
95 struct bpf_link *link = NULL; \
96 if (!ASSERT_OK_PTR(eskel, "exceptions_ext__open")) \
99 ASSERT_OK_PTR(bpf_program__name(prog), bpf_program__name(prog)); \
100 if (!ASSERT_EQ(exceptions_ext__load(eskel), load_ret, \
101 "exceptions_ext__load")) { \
102 printf("%s\n", log_buf); \
105 if (load_ret != 0) { \
106 if (!ASSERT_OK_PTR(strstr(log_buf, msg), "strstr")) { \
107 printf("%s\n", log_buf); \
111 if (!load_ret && attach_err) { \
112 if (!ASSERT_ERR_PTR(link = bpf_program__attach(prog), "attach err")) \
114 } else if (!load_ret) { \
115 if (!ASSERT_OK_PTR(link = bpf_program__attach(prog), "attach ok")) \
117 (void)(after_link); \
118 bpf_link__destroy(link); \
122 if (test__start_subtest("non-throwing fentry -> exception_cb"))
123 RUN_EXT(-EINVAL, true, ({
124 prog = eskel->progs.pfentry;
125 bpf_program__set_autoload(prog, true);
126 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
127 bpf_program__fd(skel->progs.exception_ext_mod_cb_runtime),
128 "exception_cb_mod"), "set_attach_target"))
130 }), "FENTRY/FEXIT programs cannot attach to exception callback", 0);
132 if (test__start_subtest("throwing fentry -> exception_cb"))
133 RUN_EXT(-EINVAL, true, ({
134 prog = eskel->progs.throwing_fentry;
135 bpf_program__set_autoload(prog, true);
136 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
137 bpf_program__fd(skel->progs.exception_ext_mod_cb_runtime),
138 "exception_cb_mod"), "set_attach_target"))
140 }), "FENTRY/FEXIT programs cannot attach to exception callback", 0);
142 if (test__start_subtest("non-throwing fexit -> exception_cb"))
143 RUN_EXT(-EINVAL, true, ({
144 prog = eskel->progs.pfexit;
145 bpf_program__set_autoload(prog, true);
146 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
147 bpf_program__fd(skel->progs.exception_ext_mod_cb_runtime),
148 "exception_cb_mod"), "set_attach_target"))
150 }), "FENTRY/FEXIT programs cannot attach to exception callback", 0);
152 if (test__start_subtest("throwing fexit -> exception_cb"))
153 RUN_EXT(-EINVAL, true, ({
154 prog = eskel->progs.throwing_fexit;
155 bpf_program__set_autoload(prog, true);
156 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
157 bpf_program__fd(skel->progs.exception_ext_mod_cb_runtime),
158 "exception_cb_mod"), "set_attach_target"))
160 }), "FENTRY/FEXIT programs cannot attach to exception callback", 0);
162 if (test__start_subtest("throwing extension (with custom cb) -> exception_cb"))
163 RUN_EXT(-EINVAL, true, ({
164 prog = eskel->progs.throwing_exception_cb_extension;
165 bpf_program__set_autoload(prog, true);
166 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
167 bpf_program__fd(skel->progs.exception_ext_mod_cb_runtime),
168 "exception_cb_mod"), "set_attach_target"))
170 }), "Extension programs cannot attach to exception callback", 0);
172 if (test__start_subtest("throwing extension -> global func in exception_cb"))
174 prog = eskel->progs.throwing_exception_cb_extension;
175 bpf_program__set_autoload(prog, true);
176 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
177 bpf_program__fd(skel->progs.exception_ext_mod_cb_runtime),
178 "exception_cb_mod_global"), "set_attach_target"))
180 }), "", ({ RUN_SUCCESS(exception_ext_mod_cb_runtime, 131); }));
182 if (test__start_subtest("throwing extension (with custom cb) -> global func in exception_cb"))
184 prog = eskel->progs.throwing_extension;
185 bpf_program__set_autoload(prog, true);
186 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
187 bpf_program__fd(skel->progs.exception_ext),
188 "exception_ext_global"), "set_attach_target"))
190 }), "", ({ RUN_SUCCESS(exception_ext, 128); }));
192 if (test__start_subtest("non-throwing fentry -> non-throwing subprog"))
193 /* non-throwing fentry -> non-throwing subprog : OK */
195 prog = eskel->progs.pfentry;
196 bpf_program__set_autoload(prog, true);
197 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
198 bpf_program__fd(skel->progs.exception_throw_subprog),
199 "subprog"), "set_attach_target"))
203 if (test__start_subtest("throwing fentry -> non-throwing subprog"))
204 /* throwing fentry -> non-throwing subprog : OK */
206 prog = eskel->progs.throwing_fentry;
207 bpf_program__set_autoload(prog, true);
208 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
209 bpf_program__fd(skel->progs.exception_throw_subprog),
210 "subprog"), "set_attach_target"))
214 if (test__start_subtest("non-throwing fentry -> throwing subprog"))
215 /* non-throwing fentry -> throwing subprog : OK */
217 prog = eskel->progs.pfentry;
218 bpf_program__set_autoload(prog, true);
219 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
220 bpf_program__fd(skel->progs.exception_throw_subprog),
221 "throwing_subprog"), "set_attach_target"))
225 if (test__start_subtest("throwing fentry -> throwing subprog"))
226 /* throwing fentry -> throwing subprog : OK */
228 prog = eskel->progs.throwing_fentry;
229 bpf_program__set_autoload(prog, true);
230 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
231 bpf_program__fd(skel->progs.exception_throw_subprog),
232 "throwing_subprog"), "set_attach_target"))
236 if (test__start_subtest("non-throwing fexit -> non-throwing subprog"))
237 /* non-throwing fexit -> non-throwing subprog : OK */
239 prog = eskel->progs.pfexit;
240 bpf_program__set_autoload(prog, true);
241 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
242 bpf_program__fd(skel->progs.exception_throw_subprog),
243 "subprog"), "set_attach_target"))
247 if (test__start_subtest("throwing fexit -> non-throwing subprog"))
248 /* throwing fexit -> non-throwing subprog : OK */
250 prog = eskel->progs.throwing_fexit;
251 bpf_program__set_autoload(prog, true);
252 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
253 bpf_program__fd(skel->progs.exception_throw_subprog),
254 "subprog"), "set_attach_target"))
258 if (test__start_subtest("non-throwing fexit -> throwing subprog"))
259 /* non-throwing fexit -> throwing subprog : OK */
261 prog = eskel->progs.pfexit;
262 bpf_program__set_autoload(prog, true);
263 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
264 bpf_program__fd(skel->progs.exception_throw_subprog),
265 "throwing_subprog"), "set_attach_target"))
269 if (test__start_subtest("throwing fexit -> throwing subprog"))
270 /* throwing fexit -> throwing subprog : OK */
272 prog = eskel->progs.throwing_fexit;
273 bpf_program__set_autoload(prog, true);
274 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
275 bpf_program__fd(skel->progs.exception_throw_subprog),
276 "throwing_subprog"), "set_attach_target"))
280 /* fmod_ret not allowed for subprog - Check so we remember to handle its
281 * throwing specification compatibility with target when supported.
283 if (test__start_subtest("non-throwing fmod_ret -> non-throwing subprog"))
284 RUN_EXT(-EINVAL, true, ({
285 prog = eskel->progs.pfmod_ret;
286 bpf_program__set_autoload(prog, true);
287 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
288 bpf_program__fd(skel->progs.exception_throw_subprog),
289 "subprog"), "set_attach_target"))
291 }), "can't modify return codes of BPF program", 0);
293 /* fmod_ret not allowed for subprog - Check so we remember to handle its
294 * throwing specification compatibility with target when supported.
296 if (test__start_subtest("non-throwing fmod_ret -> non-throwing global subprog"))
297 RUN_EXT(-EINVAL, true, ({
298 prog = eskel->progs.pfmod_ret;
299 bpf_program__set_autoload(prog, true);
300 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
301 bpf_program__fd(skel->progs.exception_throw_subprog),
302 "global_subprog"), "set_attach_target"))
304 }), "can't modify return codes of BPF program", 0);
306 if (test__start_subtest("non-throwing extension -> non-throwing subprog"))
307 /* non-throwing extension -> non-throwing subprog : BAD (!global) */
308 RUN_EXT(-EINVAL, true, ({
309 prog = eskel->progs.extension;
310 bpf_program__set_autoload(prog, true);
311 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
312 bpf_program__fd(skel->progs.exception_throw_subprog),
313 "subprog"), "set_attach_target"))
315 }), "subprog() is not a global function", 0);
317 if (test__start_subtest("non-throwing extension -> throwing subprog"))
318 /* non-throwing extension -> throwing subprog : BAD (!global) */
319 RUN_EXT(-EINVAL, true, ({
320 prog = eskel->progs.extension;
321 bpf_program__set_autoload(prog, true);
322 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
323 bpf_program__fd(skel->progs.exception_throw_subprog),
324 "throwing_subprog"), "set_attach_target"))
326 }), "throwing_subprog() is not a global function", 0);
328 if (test__start_subtest("non-throwing extension -> non-throwing subprog"))
329 /* non-throwing extension -> non-throwing global subprog : OK */
331 prog = eskel->progs.extension;
332 bpf_program__set_autoload(prog, true);
333 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
334 bpf_program__fd(skel->progs.exception_throw_subprog),
335 "global_subprog"), "set_attach_target"))
339 if (test__start_subtest("non-throwing extension -> throwing global subprog"))
340 /* non-throwing extension -> throwing global subprog : OK */
342 prog = eskel->progs.extension;
343 bpf_program__set_autoload(prog, true);
344 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
345 bpf_program__fd(skel->progs.exception_throw_subprog),
346 "throwing_global_subprog"), "set_attach_target"))
350 if (test__start_subtest("throwing extension -> throwing global subprog"))
351 /* throwing extension -> throwing global subprog : OK */
353 prog = eskel->progs.throwing_extension;
354 bpf_program__set_autoload(prog, true);
355 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
356 bpf_program__fd(skel->progs.exception_throw_subprog),
357 "throwing_global_subprog"), "set_attach_target"))
361 if (test__start_subtest("throwing extension -> non-throwing global subprog"))
362 /* throwing extension -> non-throwing global subprog : OK */
364 prog = eskel->progs.throwing_extension;
365 bpf_program__set_autoload(prog, true);
366 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
367 bpf_program__fd(skel->progs.exception_throw_subprog),
368 "global_subprog"), "set_attach_target"))
372 if (test__start_subtest("non-throwing extension -> main subprog"))
373 /* non-throwing extension -> main subprog : OK */
375 prog = eskel->progs.extension;
376 bpf_program__set_autoload(prog, true);
377 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
378 bpf_program__fd(skel->progs.exception_throw_subprog),
379 "exception_throw_subprog"), "set_attach_target"))
383 if (test__start_subtest("throwing extension -> main subprog"))
384 /* throwing extension -> main subprog : OK */
386 prog = eskel->progs.throwing_extension;
387 bpf_program__set_autoload(prog, true);
388 if (!ASSERT_OK(bpf_program__set_attach_target(prog,
389 bpf_program__fd(skel->progs.exception_throw_subprog),
390 "exception_throw_subprog"), "set_attach_target"))
395 exceptions_ext__destroy(eskel);
396 exceptions__destroy(skel);
399 static void test_exceptions_assertions(void)
401 RUN_TESTS(exceptions_assert);
404 void test_exceptions(void)
406 test_exceptions_success();
407 test_exceptions_failure();
408 test_exceptions_assertions();