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 #include "exceptions_dead_subprog.skel.h" 10 11 static char log_buf[1024 * 1024]; 12 13 static void test_exceptions_failure(void) 14 { 15 RUN_TESTS(exceptions_fail); 16 } 17 18 static void test_exceptions_success(void) 19 { 20 LIBBPF_OPTS(bpf_test_run_opts, ropts, 21 .data_in = &pkt_v4, 22 .data_size_in = sizeof(pkt_v4), 23 .repeat = 1, 24 ); 25 struct exceptions_ext *eskel = NULL; 26 struct exceptions *skel; 27 int ret; 28 29 skel = exceptions__open(); 30 if (!ASSERT_OK_PTR(skel, "exceptions__open")) 31 return; 32 33 ret = exceptions__load(skel); 34 if (!ASSERT_OK(ret, "exceptions__load")) 35 goto done; 36 37 if (!ASSERT_OK(bpf_map_update_elem(bpf_map__fd(skel->maps.jmp_table), &(int){0}, 38 &(int){bpf_program__fd(skel->progs.exception_tail_call_target)}, BPF_ANY), 39 "bpf_map_update_elem jmp_table")) 40 goto done; 41 42 #define RUN_SUCCESS(_prog, return_val) \ 43 if (!test__start_subtest(#_prog)) goto _prog##_##return_val; \ 44 ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs._prog), &ropts); \ 45 ASSERT_OK(ret, #_prog " prog run ret"); \ 46 ASSERT_EQ(ropts.retval, return_val, #_prog " prog run retval"); \ 47 _prog##_##return_val: 48 49 RUN_SUCCESS(exception_throw_always_1, 64); 50 RUN_SUCCESS(exception_throw_always_2, 32); 51 RUN_SUCCESS(exception_throw_unwind_1, 16); 52 RUN_SUCCESS(exception_throw_unwind_2, 32); 53 RUN_SUCCESS(exception_throw_default, 0); 54 RUN_SUCCESS(exception_throw_default_value, 5); 55 RUN_SUCCESS(exception_tail_call, 24); 56 RUN_SUCCESS(exception_ext, 0); 57 RUN_SUCCESS(exception_ext_mod_cb_runtime, 35); 58 RUN_SUCCESS(exception_throw_subprog, 1); 59 RUN_SUCCESS(exception_throw_subprog_stack_cb, 0x1234); 60 RUN_SUCCESS(exception_assert_nz_gfunc, 1); 61 RUN_SUCCESS(exception_assert_zero_gfunc, 1); 62 RUN_SUCCESS(exception_assert_neg_gfunc, 1); 63 RUN_SUCCESS(exception_assert_pos_gfunc, 1); 64 RUN_SUCCESS(exception_assert_negeq_gfunc, 1); 65 RUN_SUCCESS(exception_assert_poseq_gfunc, 1); 66 RUN_SUCCESS(exception_assert_nz_gfunc_with, 1); 67 RUN_SUCCESS(exception_assert_zero_gfunc_with, 1); 68 RUN_SUCCESS(exception_assert_neg_gfunc_with, 1); 69 RUN_SUCCESS(exception_assert_pos_gfunc_with, 1); 70 RUN_SUCCESS(exception_assert_negeq_gfunc_with, 1); 71 RUN_SUCCESS(exception_assert_poseq_gfunc_with, 1); 72 RUN_SUCCESS(exception_bad_assert_nz_gfunc, 0); 73 RUN_SUCCESS(exception_bad_assert_zero_gfunc, 0); 74 RUN_SUCCESS(exception_bad_assert_neg_gfunc, 0); 75 RUN_SUCCESS(exception_bad_assert_pos_gfunc, 0); 76 RUN_SUCCESS(exception_bad_assert_negeq_gfunc, 0); 77 RUN_SUCCESS(exception_bad_assert_poseq_gfunc, 0); 78 RUN_SUCCESS(exception_bad_assert_nz_gfunc_with, 100); 79 RUN_SUCCESS(exception_bad_assert_zero_gfunc_with, 105); 80 RUN_SUCCESS(exception_bad_assert_neg_gfunc_with, 200); 81 RUN_SUCCESS(exception_bad_assert_pos_gfunc_with, 0); 82 RUN_SUCCESS(exception_bad_assert_negeq_gfunc_with, 101); 83 RUN_SUCCESS(exception_bad_assert_poseq_gfunc_with, 99); 84 RUN_SUCCESS(exception_assert_range, 1); 85 RUN_SUCCESS(exception_assert_range_with, 1); 86 RUN_SUCCESS(exception_bad_assert_range, 0); 87 RUN_SUCCESS(exception_bad_assert_range_with, 10); 88 RUN_SUCCESS(exception_throw_from_void_global, 11); 89 90 if (skel->rodata->has_stack_arg) { 91 RUN_SUCCESS(exception_throw_stack_arg, 56); 92 RUN_SUCCESS(exception_throw_after_stack_arg, 56); 93 RUN_SUCCESS(exception_throw_subprog_stack_arg, 56); 94 RUN_SUCCESS(exception_throw_subprog_after_stack_arg, 56); 95 } 96 97 #define RUN_EXT(load_ret, attach_err, expr, msg, after_link) \ 98 { \ 99 LIBBPF_OPTS(bpf_object_open_opts, o, .kernel_log_buf = log_buf, \ 100 .kernel_log_size = sizeof(log_buf), \ 101 .kernel_log_level = 2); \ 102 exceptions_ext__destroy(eskel); \ 103 eskel = exceptions_ext__open_opts(&o); \ 104 struct bpf_program *prog = NULL; \ 105 struct bpf_link *link = NULL; \ 106 if (!ASSERT_OK_PTR(eskel, "exceptions_ext__open")) \ 107 goto done; \ 108 (expr); \ 109 ASSERT_OK_PTR(bpf_program__name(prog), bpf_program__name(prog)); \ 110 if (!ASSERT_EQ(exceptions_ext__load(eskel), load_ret, \ 111 "exceptions_ext__load")) { \ 112 printf("%s\n", log_buf); \ 113 goto done; \ 114 } \ 115 if (load_ret != 0) { \ 116 if (!ASSERT_OK_PTR(strstr(log_buf, msg), "strstr")) { \ 117 printf("%s\n", log_buf); \ 118 goto done; \ 119 } \ 120 } \ 121 if (!load_ret && attach_err) { \ 122 if (!ASSERT_ERR_PTR(link = bpf_program__attach(prog), "attach err")) \ 123 goto done; \ 124 } else if (!load_ret) { \ 125 if (!ASSERT_OK_PTR(link = bpf_program__attach(prog), "attach ok")) \ 126 goto done; \ 127 (void)(after_link); \ 128 bpf_link__destroy(link); \ 129 } \ 130 } 131 132 if (test__start_subtest("non-throwing fentry -> exception_cb")) 133 RUN_EXT(-EINVAL, true, ({ 134 prog = eskel->progs.pfentry; 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 }), "Tracing programs cannot attach to exception callback", 0); 141 142 if (test__start_subtest("throwing fentry -> exception_cb")) 143 RUN_EXT(-EINVAL, true, ({ 144 prog = eskel->progs.throwing_fentry; 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 }), "Tracing programs cannot attach to exception callback", 0); 151 152 if (test__start_subtest("non-throwing fexit -> exception_cb")) 153 RUN_EXT(-EINVAL, true, ({ 154 prog = eskel->progs.pfexit; 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 }), "Tracing programs cannot attach to exception callback", 0); 161 162 if (test__start_subtest("throwing fexit -> exception_cb")) 163 RUN_EXT(-EINVAL, true, ({ 164 prog = eskel->progs.throwing_fexit; 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 }), "Tracing programs cannot attach to exception callback", 0); 171 172 if (test__start_subtest("throwing extension (with custom cb) -> exception_cb")) 173 RUN_EXT(-EINVAL, true, ({ 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"), "set_attach_target")) 179 goto done; 180 }), "Extension programs cannot attach to exception callback", 0); 181 182 if (test__start_subtest("throwing extension -> global func in exception_cb")) 183 RUN_EXT(0, false, ({ 184 prog = eskel->progs.throwing_exception_cb_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_mod_cb_runtime), 188 "exception_cb_mod_global"), "set_attach_target")) 189 goto done; 190 }), "", ({ RUN_SUCCESS(exception_ext_mod_cb_runtime, 131); })); 191 192 if (test__start_subtest("throwing extension (with custom cb) -> global func in exception_cb")) 193 RUN_EXT(0, false, ({ 194 prog = eskel->progs.throwing_extension; 195 bpf_program__set_autoload(prog, true); 196 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 197 bpf_program__fd(skel->progs.exception_ext), 198 "exception_ext_global"), "set_attach_target")) 199 goto done; 200 }), "", ({ RUN_SUCCESS(exception_ext, 128); })); 201 202 if (test__start_subtest("non-throwing fentry -> non-throwing subprog")) 203 /* non-throwing fentry -> non-throwing subprog : OK */ 204 RUN_EXT(0, false, ({ 205 prog = eskel->progs.pfentry; 206 bpf_program__set_autoload(prog, true); 207 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 208 bpf_program__fd(skel->progs.exception_throw_subprog), 209 "subprog"), "set_attach_target")) 210 goto done; 211 }), "", 0); 212 213 if (test__start_subtest("throwing fentry -> non-throwing subprog")) 214 /* throwing fentry -> non-throwing subprog : OK */ 215 RUN_EXT(0, false, ({ 216 prog = eskel->progs.throwing_fentry; 217 bpf_program__set_autoload(prog, true); 218 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 219 bpf_program__fd(skel->progs.exception_throw_subprog), 220 "subprog"), "set_attach_target")) 221 goto done; 222 }), "", 0); 223 224 if (test__start_subtest("non-throwing fentry -> throwing subprog")) 225 /* non-throwing fentry -> throwing subprog : OK */ 226 RUN_EXT(0, false, ({ 227 prog = eskel->progs.pfentry; 228 bpf_program__set_autoload(prog, true); 229 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 230 bpf_program__fd(skel->progs.exception_throw_subprog), 231 "throwing_subprog"), "set_attach_target")) 232 goto done; 233 }), "", 0); 234 235 if (test__start_subtest("throwing fentry -> throwing subprog")) 236 /* throwing fentry -> throwing subprog : OK */ 237 RUN_EXT(0, false, ({ 238 prog = eskel->progs.throwing_fentry; 239 bpf_program__set_autoload(prog, true); 240 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 241 bpf_program__fd(skel->progs.exception_throw_subprog), 242 "throwing_subprog"), "set_attach_target")) 243 goto done; 244 }), "", 0); 245 246 if (test__start_subtest("non-throwing fexit -> non-throwing subprog")) 247 /* non-throwing fexit -> non-throwing subprog : OK */ 248 RUN_EXT(0, false, ({ 249 prog = eskel->progs.pfexit; 250 bpf_program__set_autoload(prog, true); 251 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 252 bpf_program__fd(skel->progs.exception_throw_subprog), 253 "subprog"), "set_attach_target")) 254 goto done; 255 }), "", 0); 256 257 if (test__start_subtest("throwing fexit -> non-throwing subprog")) 258 /* throwing fexit -> non-throwing subprog : OK */ 259 RUN_EXT(0, false, ({ 260 prog = eskel->progs.throwing_fexit; 261 bpf_program__set_autoload(prog, true); 262 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 263 bpf_program__fd(skel->progs.exception_throw_subprog), 264 "subprog"), "set_attach_target")) 265 goto done; 266 }), "", 0); 267 268 if (test__start_subtest("non-throwing fexit -> throwing subprog")) 269 /* non-throwing fexit -> throwing subprog : OK */ 270 RUN_EXT(0, false, ({ 271 prog = eskel->progs.pfexit; 272 bpf_program__set_autoload(prog, true); 273 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 274 bpf_program__fd(skel->progs.exception_throw_subprog), 275 "throwing_subprog"), "set_attach_target")) 276 goto done; 277 }), "", 0); 278 279 if (test__start_subtest("throwing fexit -> throwing subprog")) 280 /* throwing fexit -> throwing subprog : OK */ 281 RUN_EXT(0, false, ({ 282 prog = eskel->progs.throwing_fexit; 283 bpf_program__set_autoload(prog, true); 284 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 285 bpf_program__fd(skel->progs.exception_throw_subprog), 286 "throwing_subprog"), "set_attach_target")) 287 goto done; 288 }), "", 0); 289 290 /* fmod_ret not allowed for subprog - Check so we remember to handle its 291 * throwing specification compatibility with target when supported. 292 */ 293 if (test__start_subtest("non-throwing fmod_ret -> non-throwing subprog")) 294 RUN_EXT(-EINVAL, true, ({ 295 prog = eskel->progs.pfmod_ret; 296 bpf_program__set_autoload(prog, true); 297 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 298 bpf_program__fd(skel->progs.exception_throw_subprog), 299 "subprog"), "set_attach_target")) 300 goto done; 301 }), "can't modify return codes of BPF program", 0); 302 303 /* fmod_ret not allowed for subprog - Check so we remember to handle its 304 * throwing specification compatibility with target when supported. 305 */ 306 if (test__start_subtest("non-throwing fmod_ret -> non-throwing global subprog")) 307 RUN_EXT(-EINVAL, true, ({ 308 prog = eskel->progs.pfmod_ret; 309 bpf_program__set_autoload(prog, true); 310 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 311 bpf_program__fd(skel->progs.exception_throw_subprog), 312 "global_subprog"), "set_attach_target")) 313 goto done; 314 }), "can't modify return codes of BPF program", 0); 315 316 if (test__start_subtest("non-throwing extension -> non-throwing subprog")) 317 /* non-throwing extension -> non-throwing subprog : BAD (!global) */ 318 RUN_EXT(-EINVAL, true, ({ 319 prog = eskel->progs.extension; 320 bpf_program__set_autoload(prog, true); 321 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 322 bpf_program__fd(skel->progs.exception_throw_subprog), 323 "subprog"), "set_attach_target")) 324 goto done; 325 }), "Cannot replace static functions", 0); 326 327 if (test__start_subtest("non-throwing extension -> throwing subprog")) 328 /* non-throwing extension -> throwing subprog : BAD (!global) */ 329 RUN_EXT(-EINVAL, true, ({ 330 prog = eskel->progs.extension; 331 bpf_program__set_autoload(prog, true); 332 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 333 bpf_program__fd(skel->progs.exception_throw_subprog), 334 "throwing_subprog"), "set_attach_target")) 335 goto done; 336 }), "Cannot replace static functions", 0); 337 338 if (test__start_subtest("non-throwing extension -> non-throwing subprog")) 339 /* non-throwing extension -> non-throwing global subprog : OK */ 340 RUN_EXT(0, false, ({ 341 prog = eskel->progs.extension; 342 bpf_program__set_autoload(prog, true); 343 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 344 bpf_program__fd(skel->progs.exception_throw_subprog), 345 "global_subprog"), "set_attach_target")) 346 goto done; 347 }), "", 0); 348 349 if (test__start_subtest("non-throwing extension -> throwing global subprog")) 350 /* non-throwing extension -> throwing global subprog : OK */ 351 RUN_EXT(0, false, ({ 352 prog = eskel->progs.extension; 353 bpf_program__set_autoload(prog, true); 354 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 355 bpf_program__fd(skel->progs.exception_throw_subprog), 356 "throwing_global_subprog"), "set_attach_target")) 357 goto done; 358 }), "", 0); 359 360 if (test__start_subtest("throwing extension -> throwing global subprog")) 361 /* throwing extension -> throwing global subprog : OK */ 362 RUN_EXT(0, false, ({ 363 prog = eskel->progs.throwing_extension; 364 bpf_program__set_autoload(prog, true); 365 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 366 bpf_program__fd(skel->progs.exception_throw_subprog), 367 "throwing_global_subprog"), "set_attach_target")) 368 goto done; 369 }), "", 0); 370 371 if (test__start_subtest("throwing extension -> non-throwing global subprog")) 372 /* throwing extension -> non-throwing global subprog : OK */ 373 RUN_EXT(0, false, ({ 374 prog = eskel->progs.throwing_extension; 375 bpf_program__set_autoload(prog, true); 376 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 377 bpf_program__fd(skel->progs.exception_throw_subprog), 378 "global_subprog"), "set_attach_target")) 379 goto done; 380 }), "", 0); 381 382 if (test__start_subtest("non-throwing extension -> main subprog")) 383 /* non-throwing extension -> main subprog : OK */ 384 RUN_EXT(0, false, ({ 385 prog = eskel->progs.extension; 386 bpf_program__set_autoload(prog, true); 387 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 388 bpf_program__fd(skel->progs.exception_throw_subprog), 389 "exception_throw_subprog"), "set_attach_target")) 390 goto done; 391 }), "", 0); 392 393 if (test__start_subtest("throwing extension -> main subprog")) 394 /* throwing extension -> main subprog : OK */ 395 RUN_EXT(0, false, ({ 396 prog = eskel->progs.throwing_extension; 397 bpf_program__set_autoload(prog, true); 398 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 399 bpf_program__fd(skel->progs.exception_throw_subprog), 400 "exception_throw_subprog"), "set_attach_target")) 401 goto done; 402 }), "", 0); 403 404 done: 405 exceptions_ext__destroy(eskel); 406 exceptions__destroy(skel); 407 } 408 409 static void test_exceptions_assertions(void) 410 { 411 RUN_TESTS(exceptions_assert); 412 } 413 414 static void test_exceptions_dead_subprog(void) 415 { 416 RUN_TESTS(exceptions_dead_subprog); 417 } 418 419 void test_exceptions(void) 420 { 421 test_exceptions_success(); 422 test_exceptions_failure(); 423 test_exceptions_assertions(); 424 test_exceptions_dead_subprog(); 425 } 426