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