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_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 408 static void test_exceptions_assertions(void) 409 { 410 RUN_TESTS(exceptions_assert); 411 } 412 413 void test_exceptions(void) 414 { 415 test_exceptions_success(); 416 test_exceptions_failure(); 417 test_exceptions_assertions(); 418 } 419