1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ 3 4 #include <errno.h> 5 #include <string.h> 6 #include <linux/bpf.h> 7 #include <bpf/bpf_helpers.h> 8 #include "bpf_misc.h" 9 10 char _license[] SEC("license") = "GPL"; 11 12 #define ITER_HELPERS \ 13 __imm(bpf_iter_num_new), \ 14 __imm(bpf_iter_num_next), \ 15 __imm(bpf_iter_num_destroy) 16 17 SEC("?raw_tp") 18 __success 19 int force_clang_to_emit_btf_for_externs(void *ctx) 20 { 21 /* we need this as a workaround to enforce compiler emitting BTF 22 * information for bpf_iter_num_{new,next,destroy}() kfuncs, 23 * as, apparently, it doesn't emit it for symbols only referenced from 24 * assembly (or cleanup attribute, for that matter, as well) 25 */ 26 bpf_repeat(0); 27 28 return 0; 29 } 30 31 SEC("?raw_tp") 32 __success 33 int consume_first_item_only(void *ctx) 34 { 35 struct bpf_iter_num iter; 36 37 asm volatile ( 38 /* create iterator */ 39 "r1 = %[iter];" 40 "r2 = 0;" 41 "r3 = 1000;" 42 "call %[bpf_iter_num_new];" 43 44 /* consume first item */ 45 "r1 = %[iter];" 46 "call %[bpf_iter_num_next];" 47 48 "if r0 == 0 goto +1;" 49 "r0 = *(u32 *)(r0 + 0);" 50 51 /* destroy iterator */ 52 "r1 = %[iter];" 53 "call %[bpf_iter_num_destroy];" 54 : 55 : __imm_ptr(iter), ITER_HELPERS 56 : __clobber_common 57 ); 58 59 return 0; 60 } 61 62 SEC("?raw_tp") 63 __failure __msg("R0 invalid mem access 'scalar'") 64 int missing_null_check_fail(void *ctx) 65 { 66 struct bpf_iter_num iter; 67 68 asm volatile ( 69 /* create iterator */ 70 "r1 = %[iter];" 71 "r2 = 0;" 72 "r3 = 1000;" 73 "call %[bpf_iter_num_new];" 74 75 /* consume first element */ 76 "r1 = %[iter];" 77 "call %[bpf_iter_num_next];" 78 79 /* FAIL: deref with no NULL check */ 80 "r1 = *(u32 *)(r0 + 0);" 81 82 /* destroy iterator */ 83 "r1 = %[iter];" 84 "call %[bpf_iter_num_destroy];" 85 : 86 : __imm_ptr(iter), ITER_HELPERS 87 : __clobber_common 88 ); 89 90 return 0; 91 } 92 93 SEC("?raw_tp") 94 __failure 95 __msg("invalid access to memory, mem_size=4 off=0 size=8") 96 __msg("R0 min value is outside of the allowed memory range") 97 int wrong_sized_read_fail(void *ctx) 98 { 99 struct bpf_iter_num iter; 100 101 asm volatile ( 102 /* create iterator */ 103 "r1 = %[iter];" 104 "r2 = 0;" 105 "r3 = 1000;" 106 "call %[bpf_iter_num_new];" 107 108 /* consume first element */ 109 "r1 = %[iter];" 110 "call %[bpf_iter_num_next];" 111 112 "if r0 == 0 goto +1;" 113 /* FAIL: deref more than available 4 bytes */ 114 "r0 = *(u64 *)(r0 + 0);" 115 116 /* destroy iterator */ 117 "r1 = %[iter];" 118 "call %[bpf_iter_num_destroy];" 119 : 120 : __imm_ptr(iter), ITER_HELPERS 121 : __clobber_common 122 ); 123 124 return 0; 125 } 126 127 SEC("?raw_tp") 128 __success __log_level(2) 129 __flag(BPF_F_TEST_STATE_FREQ) 130 int simplest_loop(void *ctx) 131 { 132 struct bpf_iter_num iter; 133 134 asm volatile ( 135 "r6 = 0;" /* init sum */ 136 137 /* create iterator */ 138 "r1 = %[iter];" 139 "r2 = 0;" 140 "r3 = 10;" 141 "call %[bpf_iter_num_new];" 142 143 "1:" 144 /* consume next item */ 145 "r1 = %[iter];" 146 "call %[bpf_iter_num_next];" 147 148 "if r0 == 0 goto 2f;" 149 "r0 = *(u32 *)(r0 + 0);" 150 "r6 += r0;" /* accumulate sum */ 151 "goto 1b;" 152 153 "2:" 154 /* destroy iterator */ 155 "r1 = %[iter];" 156 "call %[bpf_iter_num_destroy];" 157 : 158 : __imm_ptr(iter), ITER_HELPERS 159 : __clobber_common, "r6" 160 ); 161 162 return 0; 163 } 164