1*57400dccSAndrii Nakryiko // SPDX-License-Identifier: GPL-2.0 2*57400dccSAndrii Nakryiko /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ 3*57400dccSAndrii Nakryiko 4*57400dccSAndrii Nakryiko #include <stdbool.h> 5*57400dccSAndrii Nakryiko #include <linux/bpf.h> 6*57400dccSAndrii Nakryiko #include <bpf/bpf_helpers.h> 7*57400dccSAndrii Nakryiko #include "bpf_misc.h" 8*57400dccSAndrii Nakryiko 9*57400dccSAndrii Nakryiko #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 10*57400dccSAndrii Nakryiko 11*57400dccSAndrii Nakryiko static volatile int zero = 0; 12*57400dccSAndrii Nakryiko 13*57400dccSAndrii Nakryiko int my_pid; 14*57400dccSAndrii Nakryiko int arr[256]; 15*57400dccSAndrii Nakryiko int small_arr[16] SEC(".data.small_arr"); 16*57400dccSAndrii Nakryiko 17*57400dccSAndrii Nakryiko #ifdef REAL_TEST 18*57400dccSAndrii Nakryiko #define MY_PID_GUARD() if (my_pid != (bpf_get_current_pid_tgid() >> 32)) return 0 19*57400dccSAndrii Nakryiko #else 20*57400dccSAndrii Nakryiko #define MY_PID_GUARD() ({ }) 21*57400dccSAndrii Nakryiko #endif 22*57400dccSAndrii Nakryiko 23*57400dccSAndrii Nakryiko SEC("?raw_tp") 24*57400dccSAndrii Nakryiko __failure __msg("math between map_value pointer and register with unbounded min value is not allowed") 25*57400dccSAndrii Nakryiko int iter_err_unsafe_c_loop(const void *ctx) 26*57400dccSAndrii Nakryiko { 27*57400dccSAndrii Nakryiko struct bpf_iter_num it; 28*57400dccSAndrii Nakryiko int *v, i = zero; /* obscure initial value of i */ 29*57400dccSAndrii Nakryiko 30*57400dccSAndrii Nakryiko MY_PID_GUARD(); 31*57400dccSAndrii Nakryiko 32*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 0, 1000); 33*57400dccSAndrii Nakryiko while ((v = bpf_iter_num_next(&it))) { 34*57400dccSAndrii Nakryiko i++; 35*57400dccSAndrii Nakryiko } 36*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 37*57400dccSAndrii Nakryiko 38*57400dccSAndrii Nakryiko small_arr[i] = 123; /* invalid */ 39*57400dccSAndrii Nakryiko 40*57400dccSAndrii Nakryiko return 0; 41*57400dccSAndrii Nakryiko } 42*57400dccSAndrii Nakryiko 43*57400dccSAndrii Nakryiko SEC("?raw_tp") 44*57400dccSAndrii Nakryiko __failure __msg("unbounded memory access") 45*57400dccSAndrii Nakryiko int iter_err_unsafe_asm_loop(const void *ctx) 46*57400dccSAndrii Nakryiko { 47*57400dccSAndrii Nakryiko struct bpf_iter_num it; 48*57400dccSAndrii Nakryiko int *v, i = 0; 49*57400dccSAndrii Nakryiko 50*57400dccSAndrii Nakryiko MY_PID_GUARD(); 51*57400dccSAndrii Nakryiko 52*57400dccSAndrii Nakryiko asm volatile ( 53*57400dccSAndrii Nakryiko "r6 = %[zero];" /* iteration counter */ 54*57400dccSAndrii Nakryiko "r1 = %[it];" /* iterator state */ 55*57400dccSAndrii Nakryiko "r2 = 0;" 56*57400dccSAndrii Nakryiko "r3 = 1000;" 57*57400dccSAndrii Nakryiko "r4 = 1;" 58*57400dccSAndrii Nakryiko "call %[bpf_iter_num_new];" 59*57400dccSAndrii Nakryiko "loop:" 60*57400dccSAndrii Nakryiko "r1 = %[it];" 61*57400dccSAndrii Nakryiko "call %[bpf_iter_num_next];" 62*57400dccSAndrii Nakryiko "if r0 == 0 goto out;" 63*57400dccSAndrii Nakryiko "r6 += 1;" 64*57400dccSAndrii Nakryiko "goto loop;" 65*57400dccSAndrii Nakryiko "out:" 66*57400dccSAndrii Nakryiko "r1 = %[it];" 67*57400dccSAndrii Nakryiko "call %[bpf_iter_num_destroy];" 68*57400dccSAndrii Nakryiko "r1 = %[small_arr];" 69*57400dccSAndrii Nakryiko "r2 = r6;" 70*57400dccSAndrii Nakryiko "r2 <<= 2;" 71*57400dccSAndrii Nakryiko "r1 += r2;" 72*57400dccSAndrii Nakryiko "*(u32 *)(r1 + 0) = r6;" /* invalid */ 73*57400dccSAndrii Nakryiko : 74*57400dccSAndrii Nakryiko : [it]"r"(&it), 75*57400dccSAndrii Nakryiko [small_arr]"p"(small_arr), 76*57400dccSAndrii Nakryiko [zero]"p"(zero), 77*57400dccSAndrii Nakryiko __imm(bpf_iter_num_new), 78*57400dccSAndrii Nakryiko __imm(bpf_iter_num_next), 79*57400dccSAndrii Nakryiko __imm(bpf_iter_num_destroy) 80*57400dccSAndrii Nakryiko : __clobber_common, "r6" 81*57400dccSAndrii Nakryiko ); 82*57400dccSAndrii Nakryiko 83*57400dccSAndrii Nakryiko return 0; 84*57400dccSAndrii Nakryiko } 85*57400dccSAndrii Nakryiko 86*57400dccSAndrii Nakryiko SEC("raw_tp") 87*57400dccSAndrii Nakryiko __success 88*57400dccSAndrii Nakryiko int iter_while_loop(const void *ctx) 89*57400dccSAndrii Nakryiko { 90*57400dccSAndrii Nakryiko struct bpf_iter_num it; 91*57400dccSAndrii Nakryiko int *v, i; 92*57400dccSAndrii Nakryiko 93*57400dccSAndrii Nakryiko MY_PID_GUARD(); 94*57400dccSAndrii Nakryiko 95*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 0, 3); 96*57400dccSAndrii Nakryiko while ((v = bpf_iter_num_next(&it))) { 97*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E1 VAL: v=%d", *v); 98*57400dccSAndrii Nakryiko } 99*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 100*57400dccSAndrii Nakryiko 101*57400dccSAndrii Nakryiko return 0; 102*57400dccSAndrii Nakryiko } 103*57400dccSAndrii Nakryiko 104*57400dccSAndrii Nakryiko SEC("raw_tp") 105*57400dccSAndrii Nakryiko __success 106*57400dccSAndrii Nakryiko int iter_while_loop_auto_cleanup(const void *ctx) 107*57400dccSAndrii Nakryiko { 108*57400dccSAndrii Nakryiko __attribute__((cleanup(bpf_iter_num_destroy))) struct bpf_iter_num it; 109*57400dccSAndrii Nakryiko int *v, i; 110*57400dccSAndrii Nakryiko 111*57400dccSAndrii Nakryiko MY_PID_GUARD(); 112*57400dccSAndrii Nakryiko 113*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 0, 3); 114*57400dccSAndrii Nakryiko while ((v = bpf_iter_num_next(&it))) { 115*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E1 VAL: v=%d", *v); 116*57400dccSAndrii Nakryiko } 117*57400dccSAndrii Nakryiko /* (!) no explicit bpf_iter_num_destroy() */ 118*57400dccSAndrii Nakryiko 119*57400dccSAndrii Nakryiko return 0; 120*57400dccSAndrii Nakryiko } 121*57400dccSAndrii Nakryiko 122*57400dccSAndrii Nakryiko SEC("raw_tp") 123*57400dccSAndrii Nakryiko __success 124*57400dccSAndrii Nakryiko int iter_for_loop(const void *ctx) 125*57400dccSAndrii Nakryiko { 126*57400dccSAndrii Nakryiko struct bpf_iter_num it; 127*57400dccSAndrii Nakryiko int *v, i; 128*57400dccSAndrii Nakryiko 129*57400dccSAndrii Nakryiko MY_PID_GUARD(); 130*57400dccSAndrii Nakryiko 131*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 5, 10); 132*57400dccSAndrii Nakryiko for (v = bpf_iter_num_next(&it); v; v = bpf_iter_num_next(&it)) { 133*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E2 VAL: v=%d", *v); 134*57400dccSAndrii Nakryiko } 135*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 136*57400dccSAndrii Nakryiko 137*57400dccSAndrii Nakryiko return 0; 138*57400dccSAndrii Nakryiko } 139*57400dccSAndrii Nakryiko 140*57400dccSAndrii Nakryiko SEC("raw_tp") 141*57400dccSAndrii Nakryiko __success 142*57400dccSAndrii Nakryiko int iter_bpf_for_each_macro(const void *ctx) 143*57400dccSAndrii Nakryiko { 144*57400dccSAndrii Nakryiko int *v; 145*57400dccSAndrii Nakryiko 146*57400dccSAndrii Nakryiko MY_PID_GUARD(); 147*57400dccSAndrii Nakryiko 148*57400dccSAndrii Nakryiko bpf_for_each(num, v, 5, 10) { 149*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E2 VAL: v=%d", *v); 150*57400dccSAndrii Nakryiko } 151*57400dccSAndrii Nakryiko 152*57400dccSAndrii Nakryiko return 0; 153*57400dccSAndrii Nakryiko } 154*57400dccSAndrii Nakryiko 155*57400dccSAndrii Nakryiko SEC("raw_tp") 156*57400dccSAndrii Nakryiko __success 157*57400dccSAndrii Nakryiko int iter_bpf_for_macro(const void *ctx) 158*57400dccSAndrii Nakryiko { 159*57400dccSAndrii Nakryiko int i; 160*57400dccSAndrii Nakryiko 161*57400dccSAndrii Nakryiko MY_PID_GUARD(); 162*57400dccSAndrii Nakryiko 163*57400dccSAndrii Nakryiko bpf_for(i, 5, 10) { 164*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E2 VAL: v=%d", i); 165*57400dccSAndrii Nakryiko } 166*57400dccSAndrii Nakryiko 167*57400dccSAndrii Nakryiko return 0; 168*57400dccSAndrii Nakryiko } 169*57400dccSAndrii Nakryiko 170*57400dccSAndrii Nakryiko SEC("raw_tp") 171*57400dccSAndrii Nakryiko __success 172*57400dccSAndrii Nakryiko int iter_pragma_unroll_loop(const void *ctx) 173*57400dccSAndrii Nakryiko { 174*57400dccSAndrii Nakryiko struct bpf_iter_num it; 175*57400dccSAndrii Nakryiko int *v, i; 176*57400dccSAndrii Nakryiko 177*57400dccSAndrii Nakryiko MY_PID_GUARD(); 178*57400dccSAndrii Nakryiko 179*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 0, 2); 180*57400dccSAndrii Nakryiko #pragma nounroll 181*57400dccSAndrii Nakryiko for (i = 0; i < 3; i++) { 182*57400dccSAndrii Nakryiko v = bpf_iter_num_next(&it); 183*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E3 VAL: i=%d v=%d", i, v ? *v : -1); 184*57400dccSAndrii Nakryiko } 185*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 186*57400dccSAndrii Nakryiko 187*57400dccSAndrii Nakryiko return 0; 188*57400dccSAndrii Nakryiko } 189*57400dccSAndrii Nakryiko 190*57400dccSAndrii Nakryiko SEC("raw_tp") 191*57400dccSAndrii Nakryiko __success 192*57400dccSAndrii Nakryiko int iter_manual_unroll_loop(const void *ctx) 193*57400dccSAndrii Nakryiko { 194*57400dccSAndrii Nakryiko struct bpf_iter_num it; 195*57400dccSAndrii Nakryiko int *v, i; 196*57400dccSAndrii Nakryiko 197*57400dccSAndrii Nakryiko MY_PID_GUARD(); 198*57400dccSAndrii Nakryiko 199*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 100, 200); 200*57400dccSAndrii Nakryiko v = bpf_iter_num_next(&it); 201*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1); 202*57400dccSAndrii Nakryiko v = bpf_iter_num_next(&it); 203*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1); 204*57400dccSAndrii Nakryiko v = bpf_iter_num_next(&it); 205*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1); 206*57400dccSAndrii Nakryiko v = bpf_iter_num_next(&it); 207*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E4 VAL: v=%d\n", v ? *v : -1); 208*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 209*57400dccSAndrii Nakryiko 210*57400dccSAndrii Nakryiko return 0; 211*57400dccSAndrii Nakryiko } 212*57400dccSAndrii Nakryiko 213*57400dccSAndrii Nakryiko SEC("raw_tp") 214*57400dccSAndrii Nakryiko __success 215*57400dccSAndrii Nakryiko int iter_multiple_sequential_loops(const void *ctx) 216*57400dccSAndrii Nakryiko { 217*57400dccSAndrii Nakryiko struct bpf_iter_num it; 218*57400dccSAndrii Nakryiko int *v, i; 219*57400dccSAndrii Nakryiko 220*57400dccSAndrii Nakryiko MY_PID_GUARD(); 221*57400dccSAndrii Nakryiko 222*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 0, 3); 223*57400dccSAndrii Nakryiko while ((v = bpf_iter_num_next(&it))) { 224*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E1 VAL: v=%d", *v); 225*57400dccSAndrii Nakryiko } 226*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 227*57400dccSAndrii Nakryiko 228*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 5, 10); 229*57400dccSAndrii Nakryiko for (v = bpf_iter_num_next(&it); v; v = bpf_iter_num_next(&it)) { 230*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E2 VAL: v=%d", *v); 231*57400dccSAndrii Nakryiko } 232*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 233*57400dccSAndrii Nakryiko 234*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 0, 2); 235*57400dccSAndrii Nakryiko #pragma nounroll 236*57400dccSAndrii Nakryiko for (i = 0; i < 3; i++) { 237*57400dccSAndrii Nakryiko v = bpf_iter_num_next(&it); 238*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E3 VAL: i=%d v=%d", i, v ? *v : -1); 239*57400dccSAndrii Nakryiko } 240*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 241*57400dccSAndrii Nakryiko 242*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 100, 200); 243*57400dccSAndrii Nakryiko v = bpf_iter_num_next(&it); 244*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1); 245*57400dccSAndrii Nakryiko v = bpf_iter_num_next(&it); 246*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1); 247*57400dccSAndrii Nakryiko v = bpf_iter_num_next(&it); 248*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1); 249*57400dccSAndrii Nakryiko v = bpf_iter_num_next(&it); 250*57400dccSAndrii Nakryiko bpf_printk("ITER_BASIC: E4 VAL: v=%d\n", v ? *v : -1); 251*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 252*57400dccSAndrii Nakryiko 253*57400dccSAndrii Nakryiko return 0; 254*57400dccSAndrii Nakryiko } 255*57400dccSAndrii Nakryiko 256*57400dccSAndrii Nakryiko SEC("raw_tp") 257*57400dccSAndrii Nakryiko __success 258*57400dccSAndrii Nakryiko int iter_limit_cond_break_loop(const void *ctx) 259*57400dccSAndrii Nakryiko { 260*57400dccSAndrii Nakryiko struct bpf_iter_num it; 261*57400dccSAndrii Nakryiko int *v, i = 0, sum = 0; 262*57400dccSAndrii Nakryiko 263*57400dccSAndrii Nakryiko MY_PID_GUARD(); 264*57400dccSAndrii Nakryiko 265*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 0, 10); 266*57400dccSAndrii Nakryiko while ((v = bpf_iter_num_next(&it))) { 267*57400dccSAndrii Nakryiko bpf_printk("ITER_SIMPLE: i=%d v=%d", i, *v); 268*57400dccSAndrii Nakryiko sum += *v; 269*57400dccSAndrii Nakryiko 270*57400dccSAndrii Nakryiko i++; 271*57400dccSAndrii Nakryiko if (i > 3) 272*57400dccSAndrii Nakryiko break; 273*57400dccSAndrii Nakryiko } 274*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 275*57400dccSAndrii Nakryiko 276*57400dccSAndrii Nakryiko bpf_printk("ITER_SIMPLE: sum=%d\n", sum); 277*57400dccSAndrii Nakryiko 278*57400dccSAndrii Nakryiko return 0; 279*57400dccSAndrii Nakryiko } 280*57400dccSAndrii Nakryiko 281*57400dccSAndrii Nakryiko SEC("raw_tp") 282*57400dccSAndrii Nakryiko __success 283*57400dccSAndrii Nakryiko int iter_obfuscate_counter(const void *ctx) 284*57400dccSAndrii Nakryiko { 285*57400dccSAndrii Nakryiko struct bpf_iter_num it; 286*57400dccSAndrii Nakryiko int *v, sum = 0; 287*57400dccSAndrii Nakryiko /* Make i's initial value unknowable for verifier to prevent it from 288*57400dccSAndrii Nakryiko * pruning if/else branch inside the loop body and marking i as precise. 289*57400dccSAndrii Nakryiko */ 290*57400dccSAndrii Nakryiko int i = zero; 291*57400dccSAndrii Nakryiko 292*57400dccSAndrii Nakryiko MY_PID_GUARD(); 293*57400dccSAndrii Nakryiko 294*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 0, 10); 295*57400dccSAndrii Nakryiko while ((v = bpf_iter_num_next(&it))) { 296*57400dccSAndrii Nakryiko int x; 297*57400dccSAndrii Nakryiko 298*57400dccSAndrii Nakryiko i += 1; 299*57400dccSAndrii Nakryiko 300*57400dccSAndrii Nakryiko /* If we initialized i as `int i = 0;` above, verifier would 301*57400dccSAndrii Nakryiko * track that i becomes 1 on first iteration after increment 302*57400dccSAndrii Nakryiko * above, and here verifier would eagerly prune else branch 303*57400dccSAndrii Nakryiko * and mark i as precise, ruining open-coded iterator logic 304*57400dccSAndrii Nakryiko * completely, as each next iteration would have a different 305*57400dccSAndrii Nakryiko * *precise* value of i, and thus there would be no 306*57400dccSAndrii Nakryiko * convergence of state. This would result in reaching maximum 307*57400dccSAndrii Nakryiko * instruction limit, no matter what the limit is. 308*57400dccSAndrii Nakryiko */ 309*57400dccSAndrii Nakryiko if (i == 1) 310*57400dccSAndrii Nakryiko x = 123; 311*57400dccSAndrii Nakryiko else 312*57400dccSAndrii Nakryiko x = i * 3 + 1; 313*57400dccSAndrii Nakryiko 314*57400dccSAndrii Nakryiko bpf_printk("ITER_OBFUSCATE_COUNTER: i=%d v=%d x=%d", i, *v, x); 315*57400dccSAndrii Nakryiko 316*57400dccSAndrii Nakryiko sum += x; 317*57400dccSAndrii Nakryiko } 318*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 319*57400dccSAndrii Nakryiko 320*57400dccSAndrii Nakryiko bpf_printk("ITER_OBFUSCATE_COUNTER: sum=%d\n", sum); 321*57400dccSAndrii Nakryiko 322*57400dccSAndrii Nakryiko return 0; 323*57400dccSAndrii Nakryiko } 324*57400dccSAndrii Nakryiko 325*57400dccSAndrii Nakryiko SEC("raw_tp") 326*57400dccSAndrii Nakryiko __success 327*57400dccSAndrii Nakryiko int iter_search_loop(const void *ctx) 328*57400dccSAndrii Nakryiko { 329*57400dccSAndrii Nakryiko struct bpf_iter_num it; 330*57400dccSAndrii Nakryiko int *v, *elem = NULL; 331*57400dccSAndrii Nakryiko bool found = false; 332*57400dccSAndrii Nakryiko 333*57400dccSAndrii Nakryiko MY_PID_GUARD(); 334*57400dccSAndrii Nakryiko 335*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 0, 10); 336*57400dccSAndrii Nakryiko 337*57400dccSAndrii Nakryiko while ((v = bpf_iter_num_next(&it))) { 338*57400dccSAndrii Nakryiko bpf_printk("ITER_SEARCH_LOOP: v=%d", *v); 339*57400dccSAndrii Nakryiko 340*57400dccSAndrii Nakryiko if (*v == 2) { 341*57400dccSAndrii Nakryiko found = true; 342*57400dccSAndrii Nakryiko elem = v; 343*57400dccSAndrii Nakryiko barrier_var(elem); 344*57400dccSAndrii Nakryiko } 345*57400dccSAndrii Nakryiko } 346*57400dccSAndrii Nakryiko 347*57400dccSAndrii Nakryiko /* should fail to verify if bpf_iter_num_destroy() is here */ 348*57400dccSAndrii Nakryiko 349*57400dccSAndrii Nakryiko if (found) 350*57400dccSAndrii Nakryiko /* here found element will be wrong, we should have copied 351*57400dccSAndrii Nakryiko * value to a variable, but here we want to make sure we can 352*57400dccSAndrii Nakryiko * access memory after the loop anyways 353*57400dccSAndrii Nakryiko */ 354*57400dccSAndrii Nakryiko bpf_printk("ITER_SEARCH_LOOP: FOUND IT = %d!\n", *elem); 355*57400dccSAndrii Nakryiko else 356*57400dccSAndrii Nakryiko bpf_printk("ITER_SEARCH_LOOP: NOT FOUND IT!\n"); 357*57400dccSAndrii Nakryiko 358*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 359*57400dccSAndrii Nakryiko 360*57400dccSAndrii Nakryiko return 0; 361*57400dccSAndrii Nakryiko } 362*57400dccSAndrii Nakryiko 363*57400dccSAndrii Nakryiko SEC("raw_tp") 364*57400dccSAndrii Nakryiko __success 365*57400dccSAndrii Nakryiko int iter_array_fill(const void *ctx) 366*57400dccSAndrii Nakryiko { 367*57400dccSAndrii Nakryiko int sum, i; 368*57400dccSAndrii Nakryiko 369*57400dccSAndrii Nakryiko MY_PID_GUARD(); 370*57400dccSAndrii Nakryiko 371*57400dccSAndrii Nakryiko bpf_for(i, 0, ARRAY_SIZE(arr)) { 372*57400dccSAndrii Nakryiko arr[i] = i * 2; 373*57400dccSAndrii Nakryiko } 374*57400dccSAndrii Nakryiko 375*57400dccSAndrii Nakryiko sum = 0; 376*57400dccSAndrii Nakryiko bpf_for(i, 0, ARRAY_SIZE(arr)) { 377*57400dccSAndrii Nakryiko sum += arr[i]; 378*57400dccSAndrii Nakryiko } 379*57400dccSAndrii Nakryiko 380*57400dccSAndrii Nakryiko bpf_printk("ITER_ARRAY_FILL: sum=%d (should be %d)\n", sum, 255 * 256); 381*57400dccSAndrii Nakryiko 382*57400dccSAndrii Nakryiko return 0; 383*57400dccSAndrii Nakryiko } 384*57400dccSAndrii Nakryiko 385*57400dccSAndrii Nakryiko static int arr2d[4][5]; 386*57400dccSAndrii Nakryiko static int arr2d_row_sums[4]; 387*57400dccSAndrii Nakryiko static int arr2d_col_sums[5]; 388*57400dccSAndrii Nakryiko 389*57400dccSAndrii Nakryiko SEC("raw_tp") 390*57400dccSAndrii Nakryiko __success 391*57400dccSAndrii Nakryiko int iter_nested_iters(const void *ctx) 392*57400dccSAndrii Nakryiko { 393*57400dccSAndrii Nakryiko int sum, row, col; 394*57400dccSAndrii Nakryiko 395*57400dccSAndrii Nakryiko MY_PID_GUARD(); 396*57400dccSAndrii Nakryiko 397*57400dccSAndrii Nakryiko bpf_for(row, 0, ARRAY_SIZE(arr2d)) { 398*57400dccSAndrii Nakryiko bpf_for( col, 0, ARRAY_SIZE(arr2d[0])) { 399*57400dccSAndrii Nakryiko arr2d[row][col] = row * col; 400*57400dccSAndrii Nakryiko } 401*57400dccSAndrii Nakryiko } 402*57400dccSAndrii Nakryiko 403*57400dccSAndrii Nakryiko /* zero-initialize sums */ 404*57400dccSAndrii Nakryiko sum = 0; 405*57400dccSAndrii Nakryiko bpf_for(row, 0, ARRAY_SIZE(arr2d)) { 406*57400dccSAndrii Nakryiko arr2d_row_sums[row] = 0; 407*57400dccSAndrii Nakryiko } 408*57400dccSAndrii Nakryiko bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) { 409*57400dccSAndrii Nakryiko arr2d_col_sums[col] = 0; 410*57400dccSAndrii Nakryiko } 411*57400dccSAndrii Nakryiko 412*57400dccSAndrii Nakryiko /* calculate sums */ 413*57400dccSAndrii Nakryiko bpf_for(row, 0, ARRAY_SIZE(arr2d)) { 414*57400dccSAndrii Nakryiko bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) { 415*57400dccSAndrii Nakryiko sum += arr2d[row][col]; 416*57400dccSAndrii Nakryiko arr2d_row_sums[row] += arr2d[row][col]; 417*57400dccSAndrii Nakryiko arr2d_col_sums[col] += arr2d[row][col]; 418*57400dccSAndrii Nakryiko } 419*57400dccSAndrii Nakryiko } 420*57400dccSAndrii Nakryiko 421*57400dccSAndrii Nakryiko bpf_printk("ITER_NESTED_ITERS: total sum=%d", sum); 422*57400dccSAndrii Nakryiko bpf_for(row, 0, ARRAY_SIZE(arr2d)) { 423*57400dccSAndrii Nakryiko bpf_printk("ITER_NESTED_ITERS: row #%d sum=%d", row, arr2d_row_sums[row]); 424*57400dccSAndrii Nakryiko } 425*57400dccSAndrii Nakryiko bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) { 426*57400dccSAndrii Nakryiko bpf_printk("ITER_NESTED_ITERS: col #%d sum=%d%s", 427*57400dccSAndrii Nakryiko col, arr2d_col_sums[col], 428*57400dccSAndrii Nakryiko col == ARRAY_SIZE(arr2d[0]) - 1 ? "\n" : ""); 429*57400dccSAndrii Nakryiko } 430*57400dccSAndrii Nakryiko 431*57400dccSAndrii Nakryiko return 0; 432*57400dccSAndrii Nakryiko } 433*57400dccSAndrii Nakryiko 434*57400dccSAndrii Nakryiko SEC("raw_tp") 435*57400dccSAndrii Nakryiko __success 436*57400dccSAndrii Nakryiko int iter_nested_deeply_iters(const void *ctx) 437*57400dccSAndrii Nakryiko { 438*57400dccSAndrii Nakryiko int sum = 0; 439*57400dccSAndrii Nakryiko 440*57400dccSAndrii Nakryiko MY_PID_GUARD(); 441*57400dccSAndrii Nakryiko 442*57400dccSAndrii Nakryiko bpf_repeat(10) { 443*57400dccSAndrii Nakryiko bpf_repeat(10) { 444*57400dccSAndrii Nakryiko bpf_repeat(10) { 445*57400dccSAndrii Nakryiko bpf_repeat(10) { 446*57400dccSAndrii Nakryiko bpf_repeat(10) { 447*57400dccSAndrii Nakryiko sum += 1; 448*57400dccSAndrii Nakryiko } 449*57400dccSAndrii Nakryiko } 450*57400dccSAndrii Nakryiko } 451*57400dccSAndrii Nakryiko } 452*57400dccSAndrii Nakryiko /* validate that we can break from inside bpf_repeat() */ 453*57400dccSAndrii Nakryiko break; 454*57400dccSAndrii Nakryiko } 455*57400dccSAndrii Nakryiko 456*57400dccSAndrii Nakryiko return sum; 457*57400dccSAndrii Nakryiko } 458*57400dccSAndrii Nakryiko 459*57400dccSAndrii Nakryiko static __noinline void fill_inner_dimension(int row) 460*57400dccSAndrii Nakryiko { 461*57400dccSAndrii Nakryiko int col; 462*57400dccSAndrii Nakryiko 463*57400dccSAndrii Nakryiko bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) { 464*57400dccSAndrii Nakryiko arr2d[row][col] = row * col; 465*57400dccSAndrii Nakryiko } 466*57400dccSAndrii Nakryiko } 467*57400dccSAndrii Nakryiko 468*57400dccSAndrii Nakryiko static __noinline int sum_inner_dimension(int row) 469*57400dccSAndrii Nakryiko { 470*57400dccSAndrii Nakryiko int sum = 0, col; 471*57400dccSAndrii Nakryiko 472*57400dccSAndrii Nakryiko bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) { 473*57400dccSAndrii Nakryiko sum += arr2d[row][col]; 474*57400dccSAndrii Nakryiko arr2d_row_sums[row] += arr2d[row][col]; 475*57400dccSAndrii Nakryiko arr2d_col_sums[col] += arr2d[row][col]; 476*57400dccSAndrii Nakryiko } 477*57400dccSAndrii Nakryiko 478*57400dccSAndrii Nakryiko return sum; 479*57400dccSAndrii Nakryiko } 480*57400dccSAndrii Nakryiko 481*57400dccSAndrii Nakryiko SEC("raw_tp") 482*57400dccSAndrii Nakryiko __success 483*57400dccSAndrii Nakryiko int iter_subprog_iters(const void *ctx) 484*57400dccSAndrii Nakryiko { 485*57400dccSAndrii Nakryiko int sum, row, col; 486*57400dccSAndrii Nakryiko 487*57400dccSAndrii Nakryiko MY_PID_GUARD(); 488*57400dccSAndrii Nakryiko 489*57400dccSAndrii Nakryiko bpf_for(row, 0, ARRAY_SIZE(arr2d)) { 490*57400dccSAndrii Nakryiko fill_inner_dimension(row); 491*57400dccSAndrii Nakryiko } 492*57400dccSAndrii Nakryiko 493*57400dccSAndrii Nakryiko /* zero-initialize sums */ 494*57400dccSAndrii Nakryiko sum = 0; 495*57400dccSAndrii Nakryiko bpf_for(row, 0, ARRAY_SIZE(arr2d)) { 496*57400dccSAndrii Nakryiko arr2d_row_sums[row] = 0; 497*57400dccSAndrii Nakryiko } 498*57400dccSAndrii Nakryiko bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) { 499*57400dccSAndrii Nakryiko arr2d_col_sums[col] = 0; 500*57400dccSAndrii Nakryiko } 501*57400dccSAndrii Nakryiko 502*57400dccSAndrii Nakryiko /* calculate sums */ 503*57400dccSAndrii Nakryiko bpf_for(row, 0, ARRAY_SIZE(arr2d)) { 504*57400dccSAndrii Nakryiko sum += sum_inner_dimension(row); 505*57400dccSAndrii Nakryiko } 506*57400dccSAndrii Nakryiko 507*57400dccSAndrii Nakryiko bpf_printk("ITER_SUBPROG_ITERS: total sum=%d", sum); 508*57400dccSAndrii Nakryiko bpf_for(row, 0, ARRAY_SIZE(arr2d)) { 509*57400dccSAndrii Nakryiko bpf_printk("ITER_SUBPROG_ITERS: row #%d sum=%d", 510*57400dccSAndrii Nakryiko row, arr2d_row_sums[row]); 511*57400dccSAndrii Nakryiko } 512*57400dccSAndrii Nakryiko bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) { 513*57400dccSAndrii Nakryiko bpf_printk("ITER_SUBPROG_ITERS: col #%d sum=%d%s", 514*57400dccSAndrii Nakryiko col, arr2d_col_sums[col], 515*57400dccSAndrii Nakryiko col == ARRAY_SIZE(arr2d[0]) - 1 ? "\n" : ""); 516*57400dccSAndrii Nakryiko } 517*57400dccSAndrii Nakryiko 518*57400dccSAndrii Nakryiko return 0; 519*57400dccSAndrii Nakryiko } 520*57400dccSAndrii Nakryiko 521*57400dccSAndrii Nakryiko struct { 522*57400dccSAndrii Nakryiko __uint(type, BPF_MAP_TYPE_ARRAY); 523*57400dccSAndrii Nakryiko __type(key, int); 524*57400dccSAndrii Nakryiko __type(value, int); 525*57400dccSAndrii Nakryiko __uint(max_entries, 1000); 526*57400dccSAndrii Nakryiko } arr_map SEC(".maps"); 527*57400dccSAndrii Nakryiko 528*57400dccSAndrii Nakryiko SEC("?raw_tp") 529*57400dccSAndrii Nakryiko __failure __msg("invalid mem access 'scalar'") 530*57400dccSAndrii Nakryiko int iter_err_too_permissive1(const void *ctx) 531*57400dccSAndrii Nakryiko { 532*57400dccSAndrii Nakryiko int *map_val = NULL; 533*57400dccSAndrii Nakryiko int key = 0; 534*57400dccSAndrii Nakryiko 535*57400dccSAndrii Nakryiko MY_PID_GUARD(); 536*57400dccSAndrii Nakryiko 537*57400dccSAndrii Nakryiko map_val = bpf_map_lookup_elem(&arr_map, &key); 538*57400dccSAndrii Nakryiko if (!map_val) 539*57400dccSAndrii Nakryiko return 0; 540*57400dccSAndrii Nakryiko 541*57400dccSAndrii Nakryiko bpf_repeat(1000000) { 542*57400dccSAndrii Nakryiko map_val = NULL; 543*57400dccSAndrii Nakryiko } 544*57400dccSAndrii Nakryiko 545*57400dccSAndrii Nakryiko *map_val = 123; 546*57400dccSAndrii Nakryiko 547*57400dccSAndrii Nakryiko return 0; 548*57400dccSAndrii Nakryiko } 549*57400dccSAndrii Nakryiko 550*57400dccSAndrii Nakryiko SEC("?raw_tp") 551*57400dccSAndrii Nakryiko __failure __msg("invalid mem access 'map_value_or_null'") 552*57400dccSAndrii Nakryiko int iter_err_too_permissive2(const void *ctx) 553*57400dccSAndrii Nakryiko { 554*57400dccSAndrii Nakryiko int *map_val = NULL; 555*57400dccSAndrii Nakryiko int key = 0; 556*57400dccSAndrii Nakryiko 557*57400dccSAndrii Nakryiko MY_PID_GUARD(); 558*57400dccSAndrii Nakryiko 559*57400dccSAndrii Nakryiko map_val = bpf_map_lookup_elem(&arr_map, &key); 560*57400dccSAndrii Nakryiko if (!map_val) 561*57400dccSAndrii Nakryiko return 0; 562*57400dccSAndrii Nakryiko 563*57400dccSAndrii Nakryiko bpf_repeat(1000000) { 564*57400dccSAndrii Nakryiko map_val = bpf_map_lookup_elem(&arr_map, &key); 565*57400dccSAndrii Nakryiko } 566*57400dccSAndrii Nakryiko 567*57400dccSAndrii Nakryiko *map_val = 123; 568*57400dccSAndrii Nakryiko 569*57400dccSAndrii Nakryiko return 0; 570*57400dccSAndrii Nakryiko } 571*57400dccSAndrii Nakryiko 572*57400dccSAndrii Nakryiko SEC("?raw_tp") 573*57400dccSAndrii Nakryiko __failure __msg("invalid mem access 'map_value_or_null'") 574*57400dccSAndrii Nakryiko int iter_err_too_permissive3(const void *ctx) 575*57400dccSAndrii Nakryiko { 576*57400dccSAndrii Nakryiko int *map_val = NULL; 577*57400dccSAndrii Nakryiko int key = 0; 578*57400dccSAndrii Nakryiko bool found = false; 579*57400dccSAndrii Nakryiko 580*57400dccSAndrii Nakryiko MY_PID_GUARD(); 581*57400dccSAndrii Nakryiko 582*57400dccSAndrii Nakryiko bpf_repeat(1000000) { 583*57400dccSAndrii Nakryiko map_val = bpf_map_lookup_elem(&arr_map, &key); 584*57400dccSAndrii Nakryiko found = true; 585*57400dccSAndrii Nakryiko } 586*57400dccSAndrii Nakryiko 587*57400dccSAndrii Nakryiko if (found) 588*57400dccSAndrii Nakryiko *map_val = 123; 589*57400dccSAndrii Nakryiko 590*57400dccSAndrii Nakryiko return 0; 591*57400dccSAndrii Nakryiko } 592*57400dccSAndrii Nakryiko 593*57400dccSAndrii Nakryiko SEC("raw_tp") 594*57400dccSAndrii Nakryiko __success 595*57400dccSAndrii Nakryiko int iter_tricky_but_fine(const void *ctx) 596*57400dccSAndrii Nakryiko { 597*57400dccSAndrii Nakryiko int *map_val = NULL; 598*57400dccSAndrii Nakryiko int key = 0; 599*57400dccSAndrii Nakryiko bool found = false; 600*57400dccSAndrii Nakryiko 601*57400dccSAndrii Nakryiko MY_PID_GUARD(); 602*57400dccSAndrii Nakryiko 603*57400dccSAndrii Nakryiko bpf_repeat(1000000) { 604*57400dccSAndrii Nakryiko map_val = bpf_map_lookup_elem(&arr_map, &key); 605*57400dccSAndrii Nakryiko if (map_val) { 606*57400dccSAndrii Nakryiko found = true; 607*57400dccSAndrii Nakryiko break; 608*57400dccSAndrii Nakryiko } 609*57400dccSAndrii Nakryiko } 610*57400dccSAndrii Nakryiko 611*57400dccSAndrii Nakryiko if (found) 612*57400dccSAndrii Nakryiko *map_val = 123; 613*57400dccSAndrii Nakryiko 614*57400dccSAndrii Nakryiko return 0; 615*57400dccSAndrii Nakryiko } 616*57400dccSAndrii Nakryiko 617*57400dccSAndrii Nakryiko #define __bpf_memzero(p, sz) bpf_probe_read_kernel((p), (sz), 0) 618*57400dccSAndrii Nakryiko 619*57400dccSAndrii Nakryiko SEC("raw_tp") 620*57400dccSAndrii Nakryiko __success 621*57400dccSAndrii Nakryiko int iter_stack_array_loop(const void *ctx) 622*57400dccSAndrii Nakryiko { 623*57400dccSAndrii Nakryiko long arr1[16], arr2[16], sum = 0; 624*57400dccSAndrii Nakryiko int *v, i; 625*57400dccSAndrii Nakryiko 626*57400dccSAndrii Nakryiko MY_PID_GUARD(); 627*57400dccSAndrii Nakryiko 628*57400dccSAndrii Nakryiko /* zero-init arr1 and arr2 in such a way that verifier doesn't know 629*57400dccSAndrii Nakryiko * it's all zeros; if we don't do that, we'll make BPF verifier track 630*57400dccSAndrii Nakryiko * all combination of zero/non-zero stack slots for arr1/arr2, which 631*57400dccSAndrii Nakryiko * will lead to O(2^(ARRAY_SIZE(arr1)+ARRAY_SIZE(arr2))) different 632*57400dccSAndrii Nakryiko * states 633*57400dccSAndrii Nakryiko */ 634*57400dccSAndrii Nakryiko __bpf_memzero(arr1, sizeof(arr1)); 635*57400dccSAndrii Nakryiko __bpf_memzero(arr2, sizeof(arr1)); 636*57400dccSAndrii Nakryiko 637*57400dccSAndrii Nakryiko /* validate that we can break and continue when using bpf_for() */ 638*57400dccSAndrii Nakryiko bpf_for(i, 0, ARRAY_SIZE(arr1)) { 639*57400dccSAndrii Nakryiko if (i & 1) { 640*57400dccSAndrii Nakryiko arr1[i] = i; 641*57400dccSAndrii Nakryiko continue; 642*57400dccSAndrii Nakryiko } else { 643*57400dccSAndrii Nakryiko arr2[i] = i; 644*57400dccSAndrii Nakryiko break; 645*57400dccSAndrii Nakryiko } 646*57400dccSAndrii Nakryiko } 647*57400dccSAndrii Nakryiko 648*57400dccSAndrii Nakryiko bpf_for(i, 0, ARRAY_SIZE(arr1)) { 649*57400dccSAndrii Nakryiko sum += arr1[i] + arr2[i]; 650*57400dccSAndrii Nakryiko } 651*57400dccSAndrii Nakryiko 652*57400dccSAndrii Nakryiko return sum; 653*57400dccSAndrii Nakryiko } 654*57400dccSAndrii Nakryiko 655*57400dccSAndrii Nakryiko static __noinline void fill(struct bpf_iter_num *it, int *arr, __u32 n, int mul) 656*57400dccSAndrii Nakryiko { 657*57400dccSAndrii Nakryiko int *t, i; 658*57400dccSAndrii Nakryiko 659*57400dccSAndrii Nakryiko while ((t = bpf_iter_num_next(it))) { 660*57400dccSAndrii Nakryiko i = *t; 661*57400dccSAndrii Nakryiko if (i >= n) 662*57400dccSAndrii Nakryiko break; 663*57400dccSAndrii Nakryiko arr[i] = i * mul; 664*57400dccSAndrii Nakryiko } 665*57400dccSAndrii Nakryiko } 666*57400dccSAndrii Nakryiko 667*57400dccSAndrii Nakryiko static __noinline int sum(struct bpf_iter_num *it, int *arr, __u32 n) 668*57400dccSAndrii Nakryiko { 669*57400dccSAndrii Nakryiko int *t, i, sum = 0;; 670*57400dccSAndrii Nakryiko 671*57400dccSAndrii Nakryiko while ((t = bpf_iter_num_next(it))) { 672*57400dccSAndrii Nakryiko i = *t; 673*57400dccSAndrii Nakryiko if (i >= n) 674*57400dccSAndrii Nakryiko break; 675*57400dccSAndrii Nakryiko sum += arr[i]; 676*57400dccSAndrii Nakryiko } 677*57400dccSAndrii Nakryiko 678*57400dccSAndrii Nakryiko return sum; 679*57400dccSAndrii Nakryiko } 680*57400dccSAndrii Nakryiko 681*57400dccSAndrii Nakryiko SEC("raw_tp") 682*57400dccSAndrii Nakryiko __success 683*57400dccSAndrii Nakryiko int iter_pass_iter_ptr_to_subprog(const void *ctx) 684*57400dccSAndrii Nakryiko { 685*57400dccSAndrii Nakryiko int arr1[16], arr2[32]; 686*57400dccSAndrii Nakryiko struct bpf_iter_num it; 687*57400dccSAndrii Nakryiko int n, sum1, sum2; 688*57400dccSAndrii Nakryiko 689*57400dccSAndrii Nakryiko MY_PID_GUARD(); 690*57400dccSAndrii Nakryiko 691*57400dccSAndrii Nakryiko /* fill arr1 */ 692*57400dccSAndrii Nakryiko n = ARRAY_SIZE(arr1); 693*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 0, n); 694*57400dccSAndrii Nakryiko fill(&it, arr1, n, 2); 695*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 696*57400dccSAndrii Nakryiko 697*57400dccSAndrii Nakryiko /* fill arr2 */ 698*57400dccSAndrii Nakryiko n = ARRAY_SIZE(arr2); 699*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 0, n); 700*57400dccSAndrii Nakryiko fill(&it, arr2, n, 10); 701*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 702*57400dccSAndrii Nakryiko 703*57400dccSAndrii Nakryiko /* sum arr1 */ 704*57400dccSAndrii Nakryiko n = ARRAY_SIZE(arr1); 705*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 0, n); 706*57400dccSAndrii Nakryiko sum1 = sum(&it, arr1, n); 707*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 708*57400dccSAndrii Nakryiko 709*57400dccSAndrii Nakryiko /* sum arr2 */ 710*57400dccSAndrii Nakryiko n = ARRAY_SIZE(arr2); 711*57400dccSAndrii Nakryiko bpf_iter_num_new(&it, 0, n); 712*57400dccSAndrii Nakryiko sum2 = sum(&it, arr2, n); 713*57400dccSAndrii Nakryiko bpf_iter_num_destroy(&it); 714*57400dccSAndrii Nakryiko 715*57400dccSAndrii Nakryiko bpf_printk("sum1=%d, sum2=%d", sum1, sum2); 716*57400dccSAndrii Nakryiko 717*57400dccSAndrii Nakryiko return 0; 718*57400dccSAndrii Nakryiko } 719*57400dccSAndrii Nakryiko 720*57400dccSAndrii Nakryiko char _license[] SEC("license") = "GPL"; 721