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