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_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
87 #define RUN_EXT(load_ret, attach_err, expr, msg, after_link) \
88 { \
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")) \
97 goto done; \
98 (expr); \
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); \
103 goto done; \
104 } \
105 if (load_ret != 0) { \
106 if (!ASSERT_OK_PTR(strstr(log_buf, msg), "strstr")) { \
107 printf("%s\n", log_buf); \
108 goto done; \
109 } \
110 } \
111 if (!load_ret && attach_err) { \
112 if (!ASSERT_ERR_PTR(link = bpf_program__attach(prog), "attach err")) \
113 goto done; \
114 } else if (!load_ret) { \
115 if (!ASSERT_OK_PTR(link = bpf_program__attach(prog), "attach ok")) \
116 goto done; \
117 (void)(after_link); \
118 bpf_link__destroy(link); \
119 } \
120 }
121
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"))
129 goto done;
130 }), "FENTRY/FEXIT programs cannot attach to exception callback", 0);
131
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"))
139 goto done;
140 }), "FENTRY/FEXIT programs cannot attach to exception callback", 0);
141
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"))
149 goto done;
150 }), "FENTRY/FEXIT programs cannot attach to exception callback", 0);
151
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"))
159 goto done;
160 }), "FENTRY/FEXIT programs cannot attach to exception callback", 0);
161
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"))
169 goto done;
170 }), "Extension programs cannot attach to exception callback", 0);
171
172 if (test__start_subtest("throwing extension -> global func in exception_cb"))
173 RUN_EXT(0, false, ({
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"))
179 goto done;
180 }), "", ({ RUN_SUCCESS(exception_ext_mod_cb_runtime, 131); }));
181
182 if (test__start_subtest("throwing extension (with custom cb) -> global func in exception_cb"))
183 RUN_EXT(0, false, ({
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"))
189 goto done;
190 }), "", ({ RUN_SUCCESS(exception_ext, 128); }));
191
192 if (test__start_subtest("non-throwing fentry -> non-throwing subprog"))
193 /* non-throwing fentry -> non-throwing subprog : OK */
194 RUN_EXT(0, false, ({
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"))
200 goto done;
201 }), "", 0);
202
203 if (test__start_subtest("throwing fentry -> non-throwing subprog"))
204 /* throwing fentry -> non-throwing subprog : OK */
205 RUN_EXT(0, false, ({
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"))
211 goto done;
212 }), "", 0);
213
214 if (test__start_subtest("non-throwing fentry -> throwing subprog"))
215 /* non-throwing fentry -> throwing subprog : OK */
216 RUN_EXT(0, false, ({
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"))
222 goto done;
223 }), "", 0);
224
225 if (test__start_subtest("throwing fentry -> throwing subprog"))
226 /* throwing fentry -> throwing subprog : OK */
227 RUN_EXT(0, false, ({
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"))
233 goto done;
234 }), "", 0);
235
236 if (test__start_subtest("non-throwing fexit -> non-throwing subprog"))
237 /* non-throwing fexit -> non-throwing subprog : OK */
238 RUN_EXT(0, false, ({
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"))
244 goto done;
245 }), "", 0);
246
247 if (test__start_subtest("throwing fexit -> non-throwing subprog"))
248 /* throwing fexit -> non-throwing subprog : OK */
249 RUN_EXT(0, false, ({
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"))
255 goto done;
256 }), "", 0);
257
258 if (test__start_subtest("non-throwing fexit -> throwing subprog"))
259 /* non-throwing fexit -> throwing subprog : OK */
260 RUN_EXT(0, false, ({
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"))
266 goto done;
267 }), "", 0);
268
269 if (test__start_subtest("throwing fexit -> throwing subprog"))
270 /* throwing fexit -> throwing subprog : OK */
271 RUN_EXT(0, false, ({
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"))
277 goto done;
278 }), "", 0);
279
280 /* fmod_ret not allowed for subprog - Check so we remember to handle its
281 * throwing specification compatibility with target when supported.
282 */
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"))
290 goto done;
291 }), "can't modify return codes of BPF program", 0);
292
293 /* fmod_ret not allowed for subprog - Check so we remember to handle its
294 * throwing specification compatibility with target when supported.
295 */
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"))
303 goto done;
304 }), "can't modify return codes of BPF program", 0);
305
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"))
314 goto done;
315 }), "subprog() is not a global function", 0);
316
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"))
325 goto done;
326 }), "throwing_subprog() is not a global function", 0);
327
328 if (test__start_subtest("non-throwing extension -> non-throwing subprog"))
329 /* non-throwing extension -> non-throwing global subprog : OK */
330 RUN_EXT(0, false, ({
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"))
336 goto done;
337 }), "", 0);
338
339 if (test__start_subtest("non-throwing extension -> throwing global subprog"))
340 /* non-throwing extension -> throwing global subprog : OK */
341 RUN_EXT(0, false, ({
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"))
347 goto done;
348 }), "", 0);
349
350 if (test__start_subtest("throwing extension -> throwing global subprog"))
351 /* throwing extension -> throwing global subprog : OK */
352 RUN_EXT(0, false, ({
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"))
358 goto done;
359 }), "", 0);
360
361 if (test__start_subtest("throwing extension -> non-throwing global subprog"))
362 /* throwing extension -> non-throwing global subprog : OK */
363 RUN_EXT(0, false, ({
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"))
369 goto done;
370 }), "", 0);
371
372 if (test__start_subtest("non-throwing extension -> main subprog"))
373 /* non-throwing extension -> main subprog : OK */
374 RUN_EXT(0, false, ({
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"))
380 goto done;
381 }), "", 0);
382
383 if (test__start_subtest("throwing extension -> main subprog"))
384 /* throwing extension -> main subprog : OK */
385 RUN_EXT(0, false, ({
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"))
391 goto done;
392 }), "", 0);
393
394 done:
395 exceptions_ext__destroy(eskel);
396 exceptions__destroy(skel);
397 }
398
test_exceptions_assertions(void)399 static void test_exceptions_assertions(void)
400 {
401 RUN_TESTS(exceptions_assert);
402 }
403
test_exceptions(void)404 void test_exceptions(void)
405 {
406 test_exceptions_success();
407 test_exceptions_failure();
408 test_exceptions_assertions();
409 }
410