Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Add tests for BPF exceptions

Add selftests to cover success and failure cases of API usage, runtime
behavior and invariants that need to be maintained for implementation
correctness.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20230912233214.1518551-18-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Kumar Kartikeya Dwivedi and committed by
Alexei Starovoitov
d2a93715 d6ea0680

+1332
+1
tools/testing/selftests/bpf/DENYLIST.aarch64
··· 1 1 bpf_cookie/multi_kprobe_attach_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3 2 2 bpf_cookie/multi_kprobe_link_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3 3 + exceptions # JIT does not support calling kfunc bpf_throw: -524 3 4 fexit_sleep # The test never returns. The remaining tests cannot start. 4 5 kprobe_multi_bench_attach # bpf_program__attach_kprobe_multi_opts unexpected error: -95 5 6 kprobe_multi_test/attach_api_addrs # bpf_program__attach_kprobe_multi_opts unexpected error: -95
+1
tools/testing/selftests/bpf/DENYLIST.s390x
··· 6 6 cgrp_local_storage # prog_attach unexpected error: -524 (trampoline) 7 7 dynptr/test_dynptr_skb_data 8 8 dynptr/test_skb_readonly 9 + exceptions # JIT does not support calling kfunc bpf_throw (exceptions) 9 10 fexit_sleep # fexit_skel_load fexit skeleton failed (trampoline) 10 11 get_stack_raw_tp # user_stack corrupted user stack (no backchain userspace) 11 12 iters/testmod_seq* # s390x doesn't support kfuncs in modules yet
+408
tools/testing/selftests/bpf/prog_tests/exceptions.c
··· 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 + }
+368
tools/testing/selftests/bpf/progs/exceptions.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <vmlinux.h> 3 + #include <bpf/bpf_tracing.h> 4 + #include <bpf/bpf_helpers.h> 5 + #include <bpf/bpf_core_read.h> 6 + #include <bpf/bpf_endian.h> 7 + #include "bpf_misc.h" 8 + #include "bpf_experimental.h" 9 + 10 + #ifndef ETH_P_IP 11 + #define ETH_P_IP 0x0800 12 + #endif 13 + 14 + struct { 15 + __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 16 + __uint(max_entries, 4); 17 + __uint(key_size, sizeof(__u32)); 18 + __uint(value_size, sizeof(__u32)); 19 + } jmp_table SEC(".maps"); 20 + 21 + static __noinline int static_func(u64 i) 22 + { 23 + bpf_throw(32); 24 + return i; 25 + } 26 + 27 + __noinline int global2static_simple(u64 i) 28 + { 29 + static_func(i + 2); 30 + return i - 1; 31 + } 32 + 33 + __noinline int global2static(u64 i) 34 + { 35 + if (i == ETH_P_IP) 36 + bpf_throw(16); 37 + return static_func(i); 38 + } 39 + 40 + static __noinline int static2global(u64 i) 41 + { 42 + return global2static(i) + i; 43 + } 44 + 45 + SEC("tc") 46 + int exception_throw_always_1(struct __sk_buff *ctx) 47 + { 48 + bpf_throw(64); 49 + return 0; 50 + } 51 + 52 + /* In this case, the global func will never be seen executing after call to 53 + * static subprog, hence verifier will DCE the remaining instructions. Ensure we 54 + * are resilient to that. 55 + */ 56 + SEC("tc") 57 + int exception_throw_always_2(struct __sk_buff *ctx) 58 + { 59 + return global2static_simple(ctx->protocol); 60 + } 61 + 62 + SEC("tc") 63 + int exception_throw_unwind_1(struct __sk_buff *ctx) 64 + { 65 + return static2global(bpf_ntohs(ctx->protocol)); 66 + } 67 + 68 + SEC("tc") 69 + int exception_throw_unwind_2(struct __sk_buff *ctx) 70 + { 71 + return static2global(bpf_ntohs(ctx->protocol) - 1); 72 + } 73 + 74 + SEC("tc") 75 + int exception_throw_default(struct __sk_buff *ctx) 76 + { 77 + bpf_throw(0); 78 + return 1; 79 + } 80 + 81 + SEC("tc") 82 + int exception_throw_default_value(struct __sk_buff *ctx) 83 + { 84 + bpf_throw(5); 85 + return 1; 86 + } 87 + 88 + SEC("tc") 89 + int exception_tail_call_target(struct __sk_buff *ctx) 90 + { 91 + bpf_throw(16); 92 + return 0; 93 + } 94 + 95 + static __noinline 96 + int exception_tail_call_subprog(struct __sk_buff *ctx) 97 + { 98 + volatile int ret = 10; 99 + 100 + bpf_tail_call_static(ctx, &jmp_table, 0); 101 + return ret; 102 + } 103 + 104 + SEC("tc") 105 + int exception_tail_call(struct __sk_buff *ctx) { 106 + volatile int ret = 0; 107 + 108 + ret = exception_tail_call_subprog(ctx); 109 + return ret + 8; 110 + } 111 + 112 + __noinline int exception_ext_global(struct __sk_buff *ctx) 113 + { 114 + volatile int ret = 0; 115 + 116 + return ret; 117 + } 118 + 119 + static __noinline int exception_ext_static(struct __sk_buff *ctx) 120 + { 121 + return exception_ext_global(ctx); 122 + } 123 + 124 + SEC("tc") 125 + int exception_ext(struct __sk_buff *ctx) 126 + { 127 + return exception_ext_static(ctx); 128 + } 129 + 130 + __noinline int exception_cb_mod_global(u64 cookie) 131 + { 132 + volatile int ret = 0; 133 + 134 + return ret; 135 + } 136 + 137 + /* Example of how the exception callback supplied during verification can still 138 + * introduce extensions by calling to dummy global functions, and alter runtime 139 + * behavior. 140 + * 141 + * Right now we don't allow freplace attachment to exception callback itself, 142 + * but if the need arises this restriction is technically feasible to relax in 143 + * the future. 144 + */ 145 + __noinline int exception_cb_mod(u64 cookie) 146 + { 147 + return exception_cb_mod_global(cookie) + cookie + 10; 148 + } 149 + 150 + SEC("tc") 151 + __exception_cb(exception_cb_mod) 152 + int exception_ext_mod_cb_runtime(struct __sk_buff *ctx) 153 + { 154 + bpf_throw(25); 155 + return 0; 156 + } 157 + 158 + __noinline static int subprog(struct __sk_buff *ctx) 159 + { 160 + return bpf_ktime_get_ns(); 161 + } 162 + 163 + __noinline static int throwing_subprog(struct __sk_buff *ctx) 164 + { 165 + if (ctx->tstamp) 166 + bpf_throw(0); 167 + return bpf_ktime_get_ns(); 168 + } 169 + 170 + __noinline int global_subprog(struct __sk_buff *ctx) 171 + { 172 + return bpf_ktime_get_ns(); 173 + } 174 + 175 + __noinline int throwing_global_subprog(struct __sk_buff *ctx) 176 + { 177 + if (ctx->tstamp) 178 + bpf_throw(0); 179 + return bpf_ktime_get_ns(); 180 + } 181 + 182 + SEC("tc") 183 + int exception_throw_subprog(struct __sk_buff *ctx) 184 + { 185 + switch (ctx->protocol) { 186 + case 1: 187 + return subprog(ctx); 188 + case 2: 189 + return global_subprog(ctx); 190 + case 3: 191 + return throwing_subprog(ctx); 192 + case 4: 193 + return throwing_global_subprog(ctx); 194 + default: 195 + break; 196 + } 197 + bpf_throw(1); 198 + return 0; 199 + } 200 + 201 + __noinline int assert_nz_gfunc(u64 c) 202 + { 203 + volatile u64 cookie = c; 204 + 205 + bpf_assert(cookie != 0); 206 + return 0; 207 + } 208 + 209 + __noinline int assert_zero_gfunc(u64 c) 210 + { 211 + volatile u64 cookie = c; 212 + 213 + bpf_assert_eq(cookie, 0); 214 + return 0; 215 + } 216 + 217 + __noinline int assert_neg_gfunc(s64 c) 218 + { 219 + volatile s64 cookie = c; 220 + 221 + bpf_assert_lt(cookie, 0); 222 + return 0; 223 + } 224 + 225 + __noinline int assert_pos_gfunc(s64 c) 226 + { 227 + volatile s64 cookie = c; 228 + 229 + bpf_assert_gt(cookie, 0); 230 + return 0; 231 + } 232 + 233 + __noinline int assert_negeq_gfunc(s64 c) 234 + { 235 + volatile s64 cookie = c; 236 + 237 + bpf_assert_le(cookie, -1); 238 + return 0; 239 + } 240 + 241 + __noinline int assert_poseq_gfunc(s64 c) 242 + { 243 + volatile s64 cookie = c; 244 + 245 + bpf_assert_ge(cookie, 1); 246 + return 0; 247 + } 248 + 249 + __noinline int assert_nz_gfunc_with(u64 c) 250 + { 251 + volatile u64 cookie = c; 252 + 253 + bpf_assert_with(cookie != 0, cookie + 100); 254 + return 0; 255 + } 256 + 257 + __noinline int assert_zero_gfunc_with(u64 c) 258 + { 259 + volatile u64 cookie = c; 260 + 261 + bpf_assert_eq_with(cookie, 0, cookie + 100); 262 + return 0; 263 + } 264 + 265 + __noinline int assert_neg_gfunc_with(s64 c) 266 + { 267 + volatile s64 cookie = c; 268 + 269 + bpf_assert_lt_with(cookie, 0, cookie + 100); 270 + return 0; 271 + } 272 + 273 + __noinline int assert_pos_gfunc_with(s64 c) 274 + { 275 + volatile s64 cookie = c; 276 + 277 + bpf_assert_gt_with(cookie, 0, cookie + 100); 278 + return 0; 279 + } 280 + 281 + __noinline int assert_negeq_gfunc_with(s64 c) 282 + { 283 + volatile s64 cookie = c; 284 + 285 + bpf_assert_le_with(cookie, -1, cookie + 100); 286 + return 0; 287 + } 288 + 289 + __noinline int assert_poseq_gfunc_with(s64 c) 290 + { 291 + volatile s64 cookie = c; 292 + 293 + bpf_assert_ge_with(cookie, 1, cookie + 100); 294 + return 0; 295 + } 296 + 297 + #define check_assert(name, cookie, tag) \ 298 + SEC("tc") \ 299 + int exception##tag##name(struct __sk_buff *ctx) \ 300 + { \ 301 + return name(cookie) + 1; \ 302 + } 303 + 304 + check_assert(assert_nz_gfunc, 5, _); 305 + check_assert(assert_zero_gfunc, 0, _); 306 + check_assert(assert_neg_gfunc, -100, _); 307 + check_assert(assert_pos_gfunc, 100, _); 308 + check_assert(assert_negeq_gfunc, -1, _); 309 + check_assert(assert_poseq_gfunc, 1, _); 310 + 311 + check_assert(assert_nz_gfunc_with, 5, _); 312 + check_assert(assert_zero_gfunc_with, 0, _); 313 + check_assert(assert_neg_gfunc_with, -100, _); 314 + check_assert(assert_pos_gfunc_with, 100, _); 315 + check_assert(assert_negeq_gfunc_with, -1, _); 316 + check_assert(assert_poseq_gfunc_with, 1, _); 317 + 318 + check_assert(assert_nz_gfunc, 0, _bad_); 319 + check_assert(assert_zero_gfunc, 5, _bad_); 320 + check_assert(assert_neg_gfunc, 100, _bad_); 321 + check_assert(assert_pos_gfunc, -100, _bad_); 322 + check_assert(assert_negeq_gfunc, 1, _bad_); 323 + check_assert(assert_poseq_gfunc, -1, _bad_); 324 + 325 + check_assert(assert_nz_gfunc_with, 0, _bad_); 326 + check_assert(assert_zero_gfunc_with, 5, _bad_); 327 + check_assert(assert_neg_gfunc_with, 100, _bad_); 328 + check_assert(assert_pos_gfunc_with, -100, _bad_); 329 + check_assert(assert_negeq_gfunc_with, 1, _bad_); 330 + check_assert(assert_poseq_gfunc_with, -1, _bad_); 331 + 332 + SEC("tc") 333 + int exception_assert_range(struct __sk_buff *ctx) 334 + { 335 + u64 time = bpf_ktime_get_ns(); 336 + 337 + bpf_assert_range(time, 0, ~0ULL); 338 + return 1; 339 + } 340 + 341 + SEC("tc") 342 + int exception_assert_range_with(struct __sk_buff *ctx) 343 + { 344 + u64 time = bpf_ktime_get_ns(); 345 + 346 + bpf_assert_range_with(time, 0, ~0ULL, 10); 347 + return 1; 348 + } 349 + 350 + SEC("tc") 351 + int exception_bad_assert_range(struct __sk_buff *ctx) 352 + { 353 + u64 time = bpf_ktime_get_ns(); 354 + 355 + bpf_assert_range(time, -100, 100); 356 + return 1; 357 + } 358 + 359 + SEC("tc") 360 + int exception_bad_assert_range_with(struct __sk_buff *ctx) 361 + { 362 + u64 time = bpf_ktime_get_ns(); 363 + 364 + bpf_assert_range_with(time, -1000, 1000, 10); 365 + return 1; 366 + } 367 + 368 + char _license[] SEC("license") = "GPL";
+135
tools/testing/selftests/bpf/progs/exceptions_assert.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <vmlinux.h> 3 + #include <limits.h> 4 + #include <bpf/bpf_tracing.h> 5 + #include <bpf/bpf_helpers.h> 6 + #include <bpf/bpf_core_read.h> 7 + #include <bpf/bpf_endian.h> 8 + #include "bpf_misc.h" 9 + #include "bpf_experimental.h" 10 + 11 + #define check_assert(type, op, name, value) \ 12 + SEC("?tc") \ 13 + __log_level(2) __failure \ 14 + int check_assert_##op##_##name(void *ctx) \ 15 + { \ 16 + type num = bpf_ktime_get_ns(); \ 17 + bpf_assert_##op(num, value); \ 18 + return *(u64 *)num; \ 19 + } 20 + 21 + __msg(": R0_w=-2147483648 R10=fp0") 22 + check_assert(s64, eq, int_min, INT_MIN); 23 + __msg(": R0_w=2147483647 R10=fp0") 24 + check_assert(s64, eq, int_max, INT_MAX); 25 + __msg(": R0_w=0 R10=fp0") 26 + check_assert(s64, eq, zero, 0); 27 + __msg(": R0_w=-9223372036854775808 R1_w=-9223372036854775808 R10=fp0") 28 + check_assert(s64, eq, llong_min, LLONG_MIN); 29 + __msg(": R0_w=9223372036854775807 R1_w=9223372036854775807 R10=fp0") 30 + check_assert(s64, eq, llong_max, LLONG_MAX); 31 + 32 + __msg(": R0_w=scalar(smax=2147483646) R10=fp0") 33 + check_assert(s64, lt, pos, INT_MAX); 34 + __msg(": R0_w=scalar(umin=9223372036854775808,var_off=(0x8000000000000000; 0x7fffffffffffffff))") 35 + check_assert(s64, lt, zero, 0); 36 + __msg(": R0_w=scalar(umin=9223372036854775808,umax=18446744071562067967,var_off=(0x8000000000000000; 0x7fffffffffffffff))") 37 + check_assert(s64, lt, neg, INT_MIN); 38 + 39 + __msg(": R0_w=scalar(smax=2147483647) R10=fp0") 40 + check_assert(s64, le, pos, INT_MAX); 41 + __msg(": R0_w=scalar(smax=0) R10=fp0") 42 + check_assert(s64, le, zero, 0); 43 + __msg(": R0_w=scalar(umin=9223372036854775808,umax=18446744071562067968,var_off=(0x8000000000000000; 0x7fffffffffffffff))") 44 + check_assert(s64, le, neg, INT_MIN); 45 + 46 + __msg(": R0_w=scalar(umin=2147483648,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff))") 47 + check_assert(s64, gt, pos, INT_MAX); 48 + __msg(": R0_w=scalar(umin=1,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff))") 49 + check_assert(s64, gt, zero, 0); 50 + __msg(": R0_w=scalar(smin=-2147483647) R10=fp0") 51 + check_assert(s64, gt, neg, INT_MIN); 52 + 53 + __msg(": R0_w=scalar(umin=2147483647,umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff))") 54 + check_assert(s64, ge, pos, INT_MAX); 55 + __msg(": R0_w=scalar(umax=9223372036854775807,var_off=(0x0; 0x7fffffffffffffff)) R10=fp0") 56 + check_assert(s64, ge, zero, 0); 57 + __msg(": R0_w=scalar(smin=-2147483648) R10=fp0") 58 + check_assert(s64, ge, neg, INT_MIN); 59 + 60 + SEC("?tc") 61 + __log_level(2) __failure 62 + __msg(": R0=0 R1=ctx(off=0,imm=0) R2=scalar(smin=-2147483646,smax=2147483645) R10=fp0") 63 + int check_assert_range_s64(struct __sk_buff *ctx) 64 + { 65 + struct bpf_sock *sk = ctx->sk; 66 + s64 num; 67 + 68 + _Static_assert(_Generic((sk->rx_queue_mapping), s32: 1, default: 0), "type match"); 69 + if (!sk) 70 + return 0; 71 + num = sk->rx_queue_mapping; 72 + bpf_assert_range(num, INT_MIN + 2, INT_MAX - 2); 73 + return *((u8 *)ctx + num); 74 + } 75 + 76 + SEC("?tc") 77 + __log_level(2) __failure 78 + __msg(": R1=ctx(off=0,imm=0) R2=scalar(umin=4096,umax=8192,var_off=(0x0; 0x3fff))") 79 + int check_assert_range_u64(struct __sk_buff *ctx) 80 + { 81 + u64 num = ctx->len; 82 + 83 + bpf_assert_range(num, 4096, 8192); 84 + return *((u8 *)ctx + num); 85 + } 86 + 87 + SEC("?tc") 88 + __log_level(2) __failure 89 + __msg(": R0=0 R1=ctx(off=0,imm=0) R2=4096 R10=fp0") 90 + int check_assert_single_range_s64(struct __sk_buff *ctx) 91 + { 92 + struct bpf_sock *sk = ctx->sk; 93 + s64 num; 94 + 95 + _Static_assert(_Generic((sk->rx_queue_mapping), s32: 1, default: 0), "type match"); 96 + if (!sk) 97 + return 0; 98 + num = sk->rx_queue_mapping; 99 + 100 + bpf_assert_range(num, 4096, 4096); 101 + return *((u8 *)ctx + num); 102 + } 103 + 104 + SEC("?tc") 105 + __log_level(2) __failure 106 + __msg(": R1=ctx(off=0,imm=0) R2=4096 R10=fp0") 107 + int check_assert_single_range_u64(struct __sk_buff *ctx) 108 + { 109 + u64 num = ctx->len; 110 + 111 + bpf_assert_range(num, 4096, 4096); 112 + return *((u8 *)ctx + num); 113 + } 114 + 115 + SEC("?tc") 116 + __log_level(2) __failure 117 + __msg(": R1=pkt(off=64,r=64,imm=0) R2=pkt_end(off=0,imm=0) R6=pkt(off=0,r=64,imm=0) R10=fp0") 118 + int check_assert_generic(struct __sk_buff *ctx) 119 + { 120 + u8 *data_end = (void *)(long)ctx->data_end; 121 + u8 *data = (void *)(long)ctx->data; 122 + 123 + bpf_assert(data + 64 <= data_end); 124 + return data[128]; 125 + } 126 + 127 + SEC("?fentry/bpf_check") 128 + __failure __msg("At program exit the register R0 has value (0x40; 0x0)") 129 + int check_assert_with_return(void *ctx) 130 + { 131 + bpf_assert_with(!ctx, 64); 132 + return 0; 133 + } 134 + 135 + char _license[] SEC("license") = "GPL";
+72
tools/testing/selftests/bpf/progs/exceptions_ext.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <vmlinux.h> 3 + #include <bpf/bpf_helpers.h> 4 + #include "bpf_experimental.h" 5 + 6 + SEC("?fentry") 7 + int pfentry(void *ctx) 8 + { 9 + return 0; 10 + } 11 + 12 + SEC("?fentry") 13 + int throwing_fentry(void *ctx) 14 + { 15 + bpf_throw(0); 16 + return 0; 17 + } 18 + 19 + __noinline int exception_cb(u64 cookie) 20 + { 21 + return cookie + 64; 22 + } 23 + 24 + SEC("?freplace") 25 + int extension(struct __sk_buff *ctx) 26 + { 27 + return 0; 28 + } 29 + 30 + SEC("?freplace") 31 + __exception_cb(exception_cb) 32 + int throwing_exception_cb_extension(u64 cookie) 33 + { 34 + bpf_throw(32); 35 + return 0; 36 + } 37 + 38 + SEC("?freplace") 39 + __exception_cb(exception_cb) 40 + int throwing_extension(struct __sk_buff *ctx) 41 + { 42 + bpf_throw(64); 43 + return 0; 44 + } 45 + 46 + SEC("?fexit") 47 + int pfexit(void *ctx) 48 + { 49 + return 0; 50 + } 51 + 52 + SEC("?fexit") 53 + int throwing_fexit(void *ctx) 54 + { 55 + bpf_throw(0); 56 + return 0; 57 + } 58 + 59 + SEC("?fmod_ret") 60 + int pfmod_ret(void *ctx) 61 + { 62 + return 0; 63 + } 64 + 65 + SEC("?fmod_ret") 66 + int throwing_fmod_ret(void *ctx) 67 + { 68 + bpf_throw(0); 69 + return 0; 70 + } 71 + 72 + char _license[] SEC("license") = "GPL";
+347
tools/testing/selftests/bpf/progs/exceptions_fail.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <vmlinux.h> 3 + #include <bpf/bpf_tracing.h> 4 + #include <bpf/bpf_helpers.h> 5 + #include <bpf/bpf_core_read.h> 6 + 7 + #include "bpf_misc.h" 8 + #include "bpf_experimental.h" 9 + 10 + extern void bpf_rcu_read_lock(void) __ksym; 11 + 12 + #define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8))) 13 + 14 + struct foo { 15 + struct bpf_rb_node node; 16 + }; 17 + 18 + struct hmap_elem { 19 + struct bpf_timer timer; 20 + }; 21 + 22 + struct { 23 + __uint(type, BPF_MAP_TYPE_HASH); 24 + __uint(max_entries, 64); 25 + __type(key, int); 26 + __type(value, struct hmap_elem); 27 + } hmap SEC(".maps"); 28 + 29 + private(A) struct bpf_spin_lock lock; 30 + private(A) struct bpf_rb_root rbtree __contains(foo, node); 31 + 32 + __noinline void *exception_cb_bad_ret_type(u64 cookie) 33 + { 34 + return NULL; 35 + } 36 + 37 + __noinline int exception_cb_bad_arg_0(void) 38 + { 39 + return 0; 40 + } 41 + 42 + __noinline int exception_cb_bad_arg_2(int a, int b) 43 + { 44 + return 0; 45 + } 46 + 47 + __noinline int exception_cb_ok_arg_small(int a) 48 + { 49 + return 0; 50 + } 51 + 52 + SEC("?tc") 53 + __exception_cb(exception_cb_bad_ret_type) 54 + __failure __msg("Global function exception_cb_bad_ret_type() doesn't return scalar.") 55 + int reject_exception_cb_type_1(struct __sk_buff *ctx) 56 + { 57 + bpf_throw(0); 58 + return 0; 59 + } 60 + 61 + SEC("?tc") 62 + __exception_cb(exception_cb_bad_arg_0) 63 + __failure __msg("exception cb only supports single integer argument") 64 + int reject_exception_cb_type_2(struct __sk_buff *ctx) 65 + { 66 + bpf_throw(0); 67 + return 0; 68 + } 69 + 70 + SEC("?tc") 71 + __exception_cb(exception_cb_bad_arg_2) 72 + __failure __msg("exception cb only supports single integer argument") 73 + int reject_exception_cb_type_3(struct __sk_buff *ctx) 74 + { 75 + bpf_throw(0); 76 + return 0; 77 + } 78 + 79 + SEC("?tc") 80 + __exception_cb(exception_cb_ok_arg_small) 81 + __success 82 + int reject_exception_cb_type_4(struct __sk_buff *ctx) 83 + { 84 + bpf_throw(0); 85 + return 0; 86 + } 87 + 88 + __noinline 89 + static int timer_cb(void *map, int *key, struct bpf_timer *timer) 90 + { 91 + bpf_throw(0); 92 + return 0; 93 + } 94 + 95 + SEC("?tc") 96 + __failure __msg("cannot be called from callback subprog") 97 + int reject_async_callback_throw(struct __sk_buff *ctx) 98 + { 99 + struct hmap_elem *elem; 100 + 101 + elem = bpf_map_lookup_elem(&hmap, &(int){0}); 102 + if (!elem) 103 + return 0; 104 + return bpf_timer_set_callback(&elem->timer, timer_cb); 105 + } 106 + 107 + __noinline static int subprog_lock(struct __sk_buff *ctx) 108 + { 109 + volatile int ret = 0; 110 + 111 + bpf_spin_lock(&lock); 112 + if (ctx->len) 113 + bpf_throw(0); 114 + return ret; 115 + } 116 + 117 + SEC("?tc") 118 + __failure __msg("function calls are not allowed while holding a lock") 119 + int reject_with_lock(void *ctx) 120 + { 121 + bpf_spin_lock(&lock); 122 + bpf_throw(0); 123 + return 0; 124 + } 125 + 126 + SEC("?tc") 127 + __failure __msg("function calls are not allowed while holding a lock") 128 + int reject_subprog_with_lock(void *ctx) 129 + { 130 + return subprog_lock(ctx); 131 + } 132 + 133 + SEC("?tc") 134 + __failure __msg("bpf_rcu_read_unlock is missing") 135 + int reject_with_rcu_read_lock(void *ctx) 136 + { 137 + bpf_rcu_read_lock(); 138 + bpf_throw(0); 139 + return 0; 140 + } 141 + 142 + __noinline static int throwing_subprog(struct __sk_buff *ctx) 143 + { 144 + if (ctx->len) 145 + bpf_throw(0); 146 + return 0; 147 + } 148 + 149 + SEC("?tc") 150 + __failure __msg("bpf_rcu_read_unlock is missing") 151 + int reject_subprog_with_rcu_read_lock(void *ctx) 152 + { 153 + bpf_rcu_read_lock(); 154 + return throwing_subprog(ctx); 155 + } 156 + 157 + static bool rbless(struct bpf_rb_node *n1, const struct bpf_rb_node *n2) 158 + { 159 + bpf_throw(0); 160 + return true; 161 + } 162 + 163 + SEC("?tc") 164 + __failure __msg("function calls are not allowed while holding a lock") 165 + int reject_with_rbtree_add_throw(void *ctx) 166 + { 167 + struct foo *f; 168 + 169 + f = bpf_obj_new(typeof(*f)); 170 + if (!f) 171 + return 0; 172 + bpf_spin_lock(&lock); 173 + bpf_rbtree_add(&rbtree, &f->node, rbless); 174 + return 0; 175 + } 176 + 177 + SEC("?tc") 178 + __failure __msg("Unreleased reference") 179 + int reject_with_reference(void *ctx) 180 + { 181 + struct foo *f; 182 + 183 + f = bpf_obj_new(typeof(*f)); 184 + if (!f) 185 + return 0; 186 + bpf_throw(0); 187 + return 0; 188 + } 189 + 190 + __noinline static int subprog_ref(struct __sk_buff *ctx) 191 + { 192 + struct foo *f; 193 + 194 + f = bpf_obj_new(typeof(*f)); 195 + if (!f) 196 + return 0; 197 + bpf_throw(0); 198 + return 0; 199 + } 200 + 201 + __noinline static int subprog_cb_ref(u32 i, void *ctx) 202 + { 203 + bpf_throw(0); 204 + return 0; 205 + } 206 + 207 + SEC("?tc") 208 + __failure __msg("Unreleased reference") 209 + int reject_with_cb_reference(void *ctx) 210 + { 211 + struct foo *f; 212 + 213 + f = bpf_obj_new(typeof(*f)); 214 + if (!f) 215 + return 0; 216 + bpf_loop(5, subprog_cb_ref, NULL, 0); 217 + return 0; 218 + } 219 + 220 + SEC("?tc") 221 + __failure __msg("cannot be called from callback") 222 + int reject_with_cb(void *ctx) 223 + { 224 + bpf_loop(5, subprog_cb_ref, NULL, 0); 225 + return 0; 226 + } 227 + 228 + SEC("?tc") 229 + __failure __msg("Unreleased reference") 230 + int reject_with_subprog_reference(void *ctx) 231 + { 232 + return subprog_ref(ctx) + 1; 233 + } 234 + 235 + __noinline int throwing_exception_cb(u64 c) 236 + { 237 + bpf_throw(0); 238 + return c; 239 + } 240 + 241 + __noinline int exception_cb1(u64 c) 242 + { 243 + return c; 244 + } 245 + 246 + __noinline int exception_cb2(u64 c) 247 + { 248 + return c; 249 + } 250 + 251 + static __noinline int static_func(struct __sk_buff *ctx) 252 + { 253 + return exception_cb1(ctx->tstamp); 254 + } 255 + 256 + __noinline int global_func(struct __sk_buff *ctx) 257 + { 258 + return exception_cb1(ctx->tstamp); 259 + } 260 + 261 + SEC("?tc") 262 + __exception_cb(throwing_exception_cb) 263 + __failure __msg("cannot be called from callback subprog") 264 + int reject_throwing_exception_cb(struct __sk_buff *ctx) 265 + { 266 + return 0; 267 + } 268 + 269 + SEC("?tc") 270 + __exception_cb(exception_cb1) 271 + __failure __msg("cannot call exception cb directly") 272 + int reject_exception_cb_call_global_func(struct __sk_buff *ctx) 273 + { 274 + return global_func(ctx); 275 + } 276 + 277 + SEC("?tc") 278 + __exception_cb(exception_cb1) 279 + __failure __msg("cannot call exception cb directly") 280 + int reject_exception_cb_call_static_func(struct __sk_buff *ctx) 281 + { 282 + return static_func(ctx); 283 + } 284 + 285 + SEC("?tc") 286 + __exception_cb(exception_cb1) 287 + __exception_cb(exception_cb2) 288 + __failure __msg("multiple exception callback tags for main subprog") 289 + int reject_multiple_exception_cb(struct __sk_buff *ctx) 290 + { 291 + bpf_throw(0); 292 + return 16; 293 + } 294 + 295 + __noinline int exception_cb_bad_ret(u64 c) 296 + { 297 + return c; 298 + } 299 + 300 + SEC("?fentry/bpf_check") 301 + __exception_cb(exception_cb_bad_ret) 302 + __failure __msg("At program exit the register R0 has unknown scalar value should") 303 + int reject_set_exception_cb_bad_ret1(void *ctx) 304 + { 305 + return 0; 306 + } 307 + 308 + SEC("?fentry/bpf_check") 309 + __failure __msg("At program exit the register R0 has value (0x40; 0x0) should") 310 + int reject_set_exception_cb_bad_ret2(void *ctx) 311 + { 312 + bpf_throw(64); 313 + return 0; 314 + } 315 + 316 + __noinline static int loop_cb1(u32 index, int *ctx) 317 + { 318 + bpf_throw(0); 319 + return 0; 320 + } 321 + 322 + __noinline static int loop_cb2(u32 index, int *ctx) 323 + { 324 + bpf_throw(0); 325 + return 0; 326 + } 327 + 328 + SEC("?tc") 329 + __failure __msg("cannot be called from callback") 330 + int reject_exception_throw_cb(struct __sk_buff *ctx) 331 + { 332 + bpf_loop(5, loop_cb1, NULL, 0); 333 + return 0; 334 + } 335 + 336 + SEC("?tc") 337 + __failure __msg("cannot be called from callback") 338 + int reject_exception_throw_cb_diff(struct __sk_buff *ctx) 339 + { 340 + if (ctx->protocol) 341 + bpf_loop(5, loop_cb1, NULL, 0); 342 + else 343 + bpf_loop(5, loop_cb2, NULL, 0); 344 + return 0; 345 + } 346 + 347 + char _license[] SEC("license") = "GPL";