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 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 399 static void test_exceptions_assertions(void) 400 { 401 RUN_TESTS(exceptions_assert); 402 } 403 404 void test_exceptions(void) 405 { 406 test_exceptions_success(); 407 test_exceptions_failure(); 408 test_exceptions_assertions(); 409 } 410