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 printf("%s\n", log_buf); \ 107 if (!ASSERT_OK_PTR(strstr(log_buf, msg), "strstr")) \ 108 goto done; \ 109 } \ 110 if (!load_ret && attach_err) { \ 111 if (!ASSERT_ERR_PTR(link = bpf_program__attach(prog), "attach err")) \ 112 goto done; \ 113 } else if (!load_ret) { \ 114 if (!ASSERT_OK_PTR(link = bpf_program__attach(prog), "attach ok")) \ 115 goto done; \ 116 (void)(after_link); \ 117 bpf_link__destroy(link); \ 118 } \ 119 } 120 121 if (test__start_subtest("non-throwing fentry -> exception_cb")) 122 RUN_EXT(-EINVAL, true, ({ 123 prog = eskel->progs.pfentry; 124 bpf_program__set_autoload(prog, true); 125 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 126 bpf_program__fd(skel->progs.exception_ext_mod_cb_runtime), 127 "exception_cb_mod"), "set_attach_target")) 128 goto done; 129 }), "FENTRY/FEXIT programs cannot attach to exception callback", 0); 130 131 if (test__start_subtest("throwing fentry -> exception_cb")) 132 RUN_EXT(-EINVAL, true, ({ 133 prog = eskel->progs.throwing_fentry; 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 }), "FENTRY/FEXIT programs cannot attach to exception callback", 0); 140 141 if (test__start_subtest("non-throwing fexit -> exception_cb")) 142 RUN_EXT(-EINVAL, true, ({ 143 prog = eskel->progs.pfexit; 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 }), "FENTRY/FEXIT programs cannot attach to exception callback", 0); 150 151 if (test__start_subtest("throwing fexit -> exception_cb")) 152 RUN_EXT(-EINVAL, true, ({ 153 prog = eskel->progs.throwing_fexit; 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 }), "FENTRY/FEXIT programs cannot attach to exception callback", 0); 160 161 if (test__start_subtest("throwing extension (with custom cb) -> exception_cb")) 162 RUN_EXT(-EINVAL, true, ({ 163 prog = eskel->progs.throwing_exception_cb_extension; 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 }), "Extension programs cannot attach to exception callback", 0); 170 171 if (test__start_subtest("throwing extension -> global func in exception_cb")) 172 RUN_EXT(0, false, ({ 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_global"), "set_attach_target")) 178 goto done; 179 }), "", ({ RUN_SUCCESS(exception_ext_mod_cb_runtime, 131); })); 180 181 if (test__start_subtest("throwing extension (with custom cb) -> global func in exception_cb")) 182 RUN_EXT(0, false, ({ 183 prog = eskel->progs.throwing_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), 187 "exception_ext_global"), "set_attach_target")) 188 goto done; 189 }), "", ({ RUN_SUCCESS(exception_ext, 128); })); 190 191 if (test__start_subtest("non-throwing fentry -> non-throwing subprog")) 192 /* non-throwing fentry -> non-throwing subprog : OK */ 193 RUN_EXT(0, false, ({ 194 prog = eskel->progs.pfentry; 195 bpf_program__set_autoload(prog, true); 196 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 197 bpf_program__fd(skel->progs.exception_throw_subprog), 198 "subprog"), "set_attach_target")) 199 goto done; 200 }), "", 0); 201 202 if (test__start_subtest("throwing fentry -> non-throwing subprog")) 203 /* throwing fentry -> non-throwing subprog : OK */ 204 RUN_EXT(0, false, ({ 205 prog = eskel->progs.throwing_fentry; 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("non-throwing fentry -> throwing subprog")) 214 /* non-throwing fentry -> throwing subprog : OK */ 215 RUN_EXT(0, false, ({ 216 prog = eskel->progs.pfentry; 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 "throwing_subprog"), "set_attach_target")) 221 goto done; 222 }), "", 0); 223 224 if (test__start_subtest("throwing fentry -> throwing subprog")) 225 /* throwing fentry -> throwing subprog : OK */ 226 RUN_EXT(0, false, ({ 227 prog = eskel->progs.throwing_fentry; 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("non-throwing fexit -> non-throwing subprog")) 236 /* non-throwing fexit -> non-throwing subprog : OK */ 237 RUN_EXT(0, false, ({ 238 prog = eskel->progs.pfexit; 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 "subprog"), "set_attach_target")) 243 goto done; 244 }), "", 0); 245 246 if (test__start_subtest("throwing fexit -> non-throwing subprog")) 247 /* throwing fexit -> non-throwing subprog : OK */ 248 RUN_EXT(0, false, ({ 249 prog = eskel->progs.throwing_fexit; 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("non-throwing fexit -> throwing subprog")) 258 /* non-throwing fexit -> throwing subprog : OK */ 259 RUN_EXT(0, false, ({ 260 prog = eskel->progs.pfexit; 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 "throwing_subprog"), "set_attach_target")) 265 goto done; 266 }), "", 0); 267 268 if (test__start_subtest("throwing fexit -> throwing subprog")) 269 /* throwing fexit -> throwing subprog : OK */ 270 RUN_EXT(0, false, ({ 271 prog = eskel->progs.throwing_fexit; 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 /* fmod_ret not allowed for subprog - Check so we remember to handle its 280 * throwing specification compatibility with target when supported. 281 */ 282 if (test__start_subtest("non-throwing fmod_ret -> non-throwing subprog")) 283 RUN_EXT(-EINVAL, true, ({ 284 prog = eskel->progs.pfmod_ret; 285 bpf_program__set_autoload(prog, true); 286 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 287 bpf_program__fd(skel->progs.exception_throw_subprog), 288 "subprog"), "set_attach_target")) 289 goto done; 290 }), "can't modify return codes of BPF program", 0); 291 292 /* fmod_ret not allowed for subprog - Check so we remember to handle its 293 * throwing specification compatibility with target when supported. 294 */ 295 if (test__start_subtest("non-throwing fmod_ret -> non-throwing global subprog")) 296 RUN_EXT(-EINVAL, true, ({ 297 prog = eskel->progs.pfmod_ret; 298 bpf_program__set_autoload(prog, true); 299 if (!ASSERT_OK(bpf_program__set_attach_target(prog, 300 bpf_program__fd(skel->progs.exception_throw_subprog), 301 "global_subprog"), "set_attach_target")) 302 goto done; 303 }), "can't modify return codes of BPF program", 0); 304 305 if (test__start_subtest("non-throwing extension -> non-throwing subprog")) 306 /* non-throwing extension -> non-throwing subprog : BAD (!global) */ 307 RUN_EXT(-EINVAL, true, ({ 308 prog = eskel->progs.extension; 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 "subprog"), "set_attach_target")) 313 goto done; 314 }), "subprog() is not a global function", 0); 315 316 if (test__start_subtest("non-throwing extension -> throwing subprog")) 317 /* non-throwing extension -> 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 "throwing_subprog"), "set_attach_target")) 324 goto done; 325 }), "throwing_subprog() is not a global function", 0); 326 327 if (test__start_subtest("non-throwing extension -> non-throwing subprog")) 328 /* non-throwing extension -> non-throwing global subprog : OK */ 329 RUN_EXT(0, false, ({ 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 "global_subprog"), "set_attach_target")) 335 goto done; 336 }), "", 0); 337 338 if (test__start_subtest("non-throwing extension -> throwing global subprog")) 339 /* non-throwing extension -> 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 "throwing_global_subprog"), "set_attach_target")) 346 goto done; 347 }), "", 0); 348 349 if (test__start_subtest("throwing extension -> throwing global subprog")) 350 /* throwing extension -> throwing global subprog : OK */ 351 RUN_EXT(0, false, ({ 352 prog = eskel->progs.throwing_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 -> non-throwing global subprog")) 361 /* throwing extension -> non-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 "global_subprog"), "set_attach_target")) 368 goto done; 369 }), "", 0); 370 371 if (test__start_subtest("non-throwing extension -> main subprog")) 372 /* non-throwing extension -> main subprog : OK */ 373 RUN_EXT(0, false, ({ 374 prog = eskel->progs.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 "exception_throw_subprog"), "set_attach_target")) 379 goto done; 380 }), "", 0); 381 382 if (test__start_subtest("throwing extension -> main subprog")) 383 /* throwing extension -> main subprog : OK */ 384 RUN_EXT(0, false, ({ 385 prog = eskel->progs.throwing_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 done: 394 exceptions_ext__destroy(eskel); 395 exceptions__destroy(skel); 396 } 397 398 static void test_exceptions_assertions(void) 399 { 400 RUN_TESTS(exceptions_assert); 401 } 402 403 void test_exceptions(void) 404 { 405 test_exceptions_success(); 406 test_exceptions_failure(); 407 test_exceptions_assertions(); 408 } 409