1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
6 #include <bpf/bpf_helpers.h>
9 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
11 static volatile int zero = 0;
15 int small_arr[16] SEC(".data.small_arr");
18 #define MY_PID_GUARD() if (my_pid != (bpf_get_current_pid_tgid() >> 32)) return 0
20 #define MY_PID_GUARD() ({ })
24 __failure __msg("math between map_value pointer and register with unbounded min value is not allowed")
25 int iter_err_unsafe_c_loop(const void *ctx)
27 struct bpf_iter_num it;
28 int *v, i = zero; /* obscure initial value of i */
32 bpf_iter_num_new(&it, 0, 1000);
33 while ((v = bpf_iter_num_next(&it))) {
36 bpf_iter_num_destroy(&it);
38 small_arr[i] = 123; /* invalid */
44 __failure __msg("unbounded memory access")
45 int iter_err_unsafe_asm_loop(const void *ctx)
47 struct bpf_iter_num it;
52 "r6 = %[zero];" /* iteration counter */
53 "r1 = %[it];" /* iterator state */
57 "call %[bpf_iter_num_new];"
60 "call %[bpf_iter_num_next];"
61 "if r0 == 0 goto out;"
66 "call %[bpf_iter_num_destroy];"
71 "*(u32 *)(r1 + 0) = r6;" /* invalid */
74 [small_arr]"p"(small_arr),
76 __imm(bpf_iter_num_new),
77 __imm(bpf_iter_num_next),
78 __imm(bpf_iter_num_destroy)
79 : __clobber_common, "r6"
87 int iter_while_loop(const void *ctx)
89 struct bpf_iter_num it;
94 bpf_iter_num_new(&it, 0, 3);
95 while ((v = bpf_iter_num_next(&it))) {
96 bpf_printk("ITER_BASIC: E1 VAL: v=%d", *v);
98 bpf_iter_num_destroy(&it);
105 int iter_while_loop_auto_cleanup(const void *ctx)
107 __attribute__((cleanup(bpf_iter_num_destroy))) struct bpf_iter_num it;
112 bpf_iter_num_new(&it, 0, 3);
113 while ((v = bpf_iter_num_next(&it))) {
114 bpf_printk("ITER_BASIC: E1 VAL: v=%d", *v);
116 /* (!) no explicit bpf_iter_num_destroy() */
123 int iter_for_loop(const void *ctx)
125 struct bpf_iter_num it;
130 bpf_iter_num_new(&it, 5, 10);
131 for (v = bpf_iter_num_next(&it); v; v = bpf_iter_num_next(&it)) {
132 bpf_printk("ITER_BASIC: E2 VAL: v=%d", *v);
134 bpf_iter_num_destroy(&it);
141 int iter_bpf_for_each_macro(const void *ctx)
147 bpf_for_each(num, v, 5, 10) {
148 bpf_printk("ITER_BASIC: E2 VAL: v=%d", *v);
156 int iter_bpf_for_macro(const void *ctx)
163 bpf_printk("ITER_BASIC: E2 VAL: v=%d", i);
171 int iter_pragma_unroll_loop(const void *ctx)
173 struct bpf_iter_num it;
178 bpf_iter_num_new(&it, 0, 2);
180 for (i = 0; i < 3; i++) {
181 v = bpf_iter_num_next(&it);
182 bpf_printk("ITER_BASIC: E3 VAL: i=%d v=%d", i, v ? *v : -1);
184 bpf_iter_num_destroy(&it);
191 int iter_manual_unroll_loop(const void *ctx)
193 struct bpf_iter_num it;
198 bpf_iter_num_new(&it, 100, 200);
199 v = bpf_iter_num_next(&it);
200 bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
201 v = bpf_iter_num_next(&it);
202 bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
203 v = bpf_iter_num_next(&it);
204 bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
205 v = bpf_iter_num_next(&it);
206 bpf_printk("ITER_BASIC: E4 VAL: v=%d\n", v ? *v : -1);
207 bpf_iter_num_destroy(&it);
214 int iter_multiple_sequential_loops(const void *ctx)
216 struct bpf_iter_num it;
221 bpf_iter_num_new(&it, 0, 3);
222 while ((v = bpf_iter_num_next(&it))) {
223 bpf_printk("ITER_BASIC: E1 VAL: v=%d", *v);
225 bpf_iter_num_destroy(&it);
227 bpf_iter_num_new(&it, 5, 10);
228 for (v = bpf_iter_num_next(&it); v; v = bpf_iter_num_next(&it)) {
229 bpf_printk("ITER_BASIC: E2 VAL: v=%d", *v);
231 bpf_iter_num_destroy(&it);
233 bpf_iter_num_new(&it, 0, 2);
235 for (i = 0; i < 3; i++) {
236 v = bpf_iter_num_next(&it);
237 bpf_printk("ITER_BASIC: E3 VAL: i=%d v=%d", i, v ? *v : -1);
239 bpf_iter_num_destroy(&it);
241 bpf_iter_num_new(&it, 100, 200);
242 v = bpf_iter_num_next(&it);
243 bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
244 v = bpf_iter_num_next(&it);
245 bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
246 v = bpf_iter_num_next(&it);
247 bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
248 v = bpf_iter_num_next(&it);
249 bpf_printk("ITER_BASIC: E4 VAL: v=%d\n", v ? *v : -1);
250 bpf_iter_num_destroy(&it);
257 int iter_limit_cond_break_loop(const void *ctx)
259 struct bpf_iter_num it;
260 int *v, i = 0, sum = 0;
264 bpf_iter_num_new(&it, 0, 10);
265 while ((v = bpf_iter_num_next(&it))) {
266 bpf_printk("ITER_SIMPLE: i=%d v=%d", i, *v);
273 bpf_iter_num_destroy(&it);
275 bpf_printk("ITER_SIMPLE: sum=%d\n", sum);
282 int iter_obfuscate_counter(const void *ctx)
284 struct bpf_iter_num it;
286 /* Make i's initial value unknowable for verifier to prevent it from
287 * pruning if/else branch inside the loop body and marking i as precise.
293 bpf_iter_num_new(&it, 0, 10);
294 while ((v = bpf_iter_num_next(&it))) {
299 /* If we initialized i as `int i = 0;` above, verifier would
300 * track that i becomes 1 on first iteration after increment
301 * above, and here verifier would eagerly prune else branch
302 * and mark i as precise, ruining open-coded iterator logic
303 * completely, as each next iteration would have a different
304 * *precise* value of i, and thus there would be no
305 * convergence of state. This would result in reaching maximum
306 * instruction limit, no matter what the limit is.
313 bpf_printk("ITER_OBFUSCATE_COUNTER: i=%d v=%d x=%d", i, *v, x);
317 bpf_iter_num_destroy(&it);
319 bpf_printk("ITER_OBFUSCATE_COUNTER: sum=%d\n", sum);
326 int iter_search_loop(const void *ctx)
328 struct bpf_iter_num it;
329 int *v, *elem = NULL;
334 bpf_iter_num_new(&it, 0, 10);
336 while ((v = bpf_iter_num_next(&it))) {
337 bpf_printk("ITER_SEARCH_LOOP: v=%d", *v);
346 /* should fail to verify if bpf_iter_num_destroy() is here */
349 /* here found element will be wrong, we should have copied
350 * value to a variable, but here we want to make sure we can
351 * access memory after the loop anyways
353 bpf_printk("ITER_SEARCH_LOOP: FOUND IT = %d!\n", *elem);
355 bpf_printk("ITER_SEARCH_LOOP: NOT FOUND IT!\n");
357 bpf_iter_num_destroy(&it);
364 int iter_array_fill(const void *ctx)
370 bpf_for(i, 0, ARRAY_SIZE(arr)) {
375 bpf_for(i, 0, ARRAY_SIZE(arr)) {
379 bpf_printk("ITER_ARRAY_FILL: sum=%d (should be %d)\n", sum, 255 * 256);
384 static int arr2d[4][5];
385 static int arr2d_row_sums[4];
386 static int arr2d_col_sums[5];
390 int iter_nested_iters(const void *ctx)
396 bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
397 bpf_for( col, 0, ARRAY_SIZE(arr2d[0])) {
398 arr2d[row][col] = row * col;
402 /* zero-initialize sums */
404 bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
405 arr2d_row_sums[row] = 0;
407 bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
408 arr2d_col_sums[col] = 0;
412 bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
413 bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
414 sum += arr2d[row][col];
415 arr2d_row_sums[row] += arr2d[row][col];
416 arr2d_col_sums[col] += arr2d[row][col];
420 bpf_printk("ITER_NESTED_ITERS: total sum=%d", sum);
421 bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
422 bpf_printk("ITER_NESTED_ITERS: row #%d sum=%d", row, arr2d_row_sums[row]);
424 bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
425 bpf_printk("ITER_NESTED_ITERS: col #%d sum=%d%s",
426 col, arr2d_col_sums[col],
427 col == ARRAY_SIZE(arr2d[0]) - 1 ? "\n" : "");
435 int iter_nested_deeply_iters(const void *ctx)
451 /* validate that we can break from inside bpf_repeat() */
458 static __noinline void fill_inner_dimension(int row)
462 bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
463 arr2d[row][col] = row * col;
467 static __noinline int sum_inner_dimension(int row)
471 bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
472 sum += arr2d[row][col];
473 arr2d_row_sums[row] += arr2d[row][col];
474 arr2d_col_sums[col] += arr2d[row][col];
482 int iter_subprog_iters(const void *ctx)
488 bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
489 fill_inner_dimension(row);
492 /* zero-initialize sums */
494 bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
495 arr2d_row_sums[row] = 0;
497 bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
498 arr2d_col_sums[col] = 0;
502 bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
503 sum += sum_inner_dimension(row);
506 bpf_printk("ITER_SUBPROG_ITERS: total sum=%d", sum);
507 bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
508 bpf_printk("ITER_SUBPROG_ITERS: row #%d sum=%d",
509 row, arr2d_row_sums[row]);
511 bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
512 bpf_printk("ITER_SUBPROG_ITERS: col #%d sum=%d%s",
513 col, arr2d_col_sums[col],
514 col == ARRAY_SIZE(arr2d[0]) - 1 ? "\n" : "");
521 __uint(type, BPF_MAP_TYPE_ARRAY);
524 __uint(max_entries, 1000);
525 } arr_map SEC(".maps");
528 __failure __msg("invalid mem access 'scalar'")
529 int iter_err_too_permissive1(const void *ctx)
536 map_val = bpf_map_lookup_elem(&arr_map, &key);
540 bpf_repeat(1000000) {
550 __failure __msg("invalid mem access 'map_value_or_null'")
551 int iter_err_too_permissive2(const void *ctx)
558 map_val = bpf_map_lookup_elem(&arr_map, &key);
562 bpf_repeat(1000000) {
563 map_val = bpf_map_lookup_elem(&arr_map, &key);
572 __failure __msg("invalid mem access 'map_value_or_null'")
573 int iter_err_too_permissive3(const void *ctx)
581 bpf_repeat(1000000) {
582 map_val = bpf_map_lookup_elem(&arr_map, &key);
594 int iter_tricky_but_fine(const void *ctx)
602 bpf_repeat(1000000) {
603 map_val = bpf_map_lookup_elem(&arr_map, &key);
616 #define __bpf_memzero(p, sz) bpf_probe_read_kernel((p), (sz), 0)
620 int iter_stack_array_loop(const void *ctx)
622 long arr1[16], arr2[16], sum = 0;
627 /* zero-init arr1 and arr2 in such a way that verifier doesn't know
628 * it's all zeros; if we don't do that, we'll make BPF verifier track
629 * all combination of zero/non-zero stack slots for arr1/arr2, which
630 * will lead to O(2^(ARRAY_SIZE(arr1)+ARRAY_SIZE(arr2))) different
633 __bpf_memzero(arr1, sizeof(arr1));
634 __bpf_memzero(arr2, sizeof(arr1));
636 /* validate that we can break and continue when using bpf_for() */
637 bpf_for(i, 0, ARRAY_SIZE(arr1)) {
647 bpf_for(i, 0, ARRAY_SIZE(arr1)) {
648 sum += arr1[i] + arr2[i];
654 static __noinline void fill(struct bpf_iter_num *it, int *arr, __u32 n, int mul)
658 while ((t = bpf_iter_num_next(it))) {
666 static __noinline int sum(struct bpf_iter_num *it, int *arr, __u32 n)
670 while ((t = bpf_iter_num_next(it))) {
682 int iter_pass_iter_ptr_to_subprog(const void *ctx)
684 int arr1[16], arr2[32];
685 struct bpf_iter_num it;
691 n = ARRAY_SIZE(arr1);
692 bpf_iter_num_new(&it, 0, n);
693 fill(&it, arr1, n, 2);
694 bpf_iter_num_destroy(&it);
697 n = ARRAY_SIZE(arr2);
698 bpf_iter_num_new(&it, 0, n);
699 fill(&it, arr2, n, 10);
700 bpf_iter_num_destroy(&it);
703 n = ARRAY_SIZE(arr1);
704 bpf_iter_num_new(&it, 0, n);
705 sum1 = sum(&it, arr1, n);
706 bpf_iter_num_destroy(&it);
709 n = ARRAY_SIZE(arr2);
710 bpf_iter_num_new(&it, 0, n);
711 sum2 = sum(&it, arr2, n);
712 bpf_iter_num_destroy(&it);
714 bpf_printk("sum1=%d, sum2=%d", sum1, sum2);
719 char _license[] SEC("license") = "GPL";