1 // SPDX-License-Identifier: GPL-2.0 2 /* Converted from tools/testing/selftests/bpf/verifier/loops1.c */ 3 4 #include <linux/bpf.h> 5 #include <bpf/bpf_helpers.h> 6 #include "bpf_misc.h" 7 8 SEC("xdp") 9 __description("bounded loop, count to 4") 10 __success __retval(4) bounded_loop_count_to_4(void)11__naked void bounded_loop_count_to_4(void) 12 { 13 asm volatile (" \ 14 r0 = 0; \ 15 l0_%=: r0 += 1; \ 16 if r0 < 4 goto l0_%=; \ 17 exit; \ 18 " ::: __clobber_all); 19 } 20 21 SEC("tracepoint") 22 __description("bounded loop, count to 20") 23 __success bounded_loop_count_to_20(void)24__naked void bounded_loop_count_to_20(void) 25 { 26 asm volatile (" \ 27 r0 = 0; \ 28 l0_%=: r0 += 3; \ 29 if r0 < 20 goto l0_%=; \ 30 exit; \ 31 " ::: __clobber_all); 32 } 33 34 SEC("tracepoint") 35 __description("bounded loop, count from positive unknown to 4") 36 __success from_positive_unknown_to_4(void)37__naked void from_positive_unknown_to_4(void) 38 { 39 asm volatile (" \ 40 call %[bpf_get_prandom_u32]; \ 41 if r0 s< 0 goto l0_%=; \ 42 l1_%=: r0 += 1; \ 43 if r0 < 4 goto l1_%=; \ 44 l0_%=: exit; \ 45 " : 46 : __imm(bpf_get_prandom_u32) 47 : __clobber_all); 48 } 49 50 SEC("tracepoint") 51 __description("bounded loop, count from totally unknown to 4") 52 __success from_totally_unknown_to_4(void)53__naked void from_totally_unknown_to_4(void) 54 { 55 asm volatile (" \ 56 call %[bpf_get_prandom_u32]; \ 57 l0_%=: r0 += 1; \ 58 if r0 < 4 goto l0_%=; \ 59 exit; \ 60 " : 61 : __imm(bpf_get_prandom_u32) 62 : __clobber_all); 63 } 64 65 SEC("tracepoint") 66 __description("bounded loop, count to 4 with equality") 67 __success count_to_4_with_equality(void)68__naked void count_to_4_with_equality(void) 69 { 70 asm volatile (" \ 71 r0 = 0; \ 72 l0_%=: r0 += 1; \ 73 if r0 != 4 goto l0_%=; \ 74 exit; \ 75 " ::: __clobber_all); 76 } 77 78 SEC("socket") 79 __description("bounded loop, start in the middle") 80 __success 81 __failure_unpriv __msg_unpriv("back-edge") loop_start_in_the_middle(void)82__naked void loop_start_in_the_middle(void) 83 { 84 asm volatile (" \ 85 r0 = 0; \ 86 goto l0_%=; \ 87 l1_%=: r0 += 1; \ 88 l0_%=: if r0 < 4 goto l1_%=; \ 89 exit; \ 90 " ::: __clobber_all); 91 } 92 93 SEC("xdp") 94 __description("bounded loop containing a forward jump") 95 __success __retval(4) loop_containing_a_forward_jump(void)96__naked void loop_containing_a_forward_jump(void) 97 { 98 asm volatile (" \ 99 r0 = 0; \ 100 l1_%=: r0 += 1; \ 101 if r0 == r0 goto l0_%=; \ 102 l0_%=: if r0 < 4 goto l1_%=; \ 103 exit; \ 104 " ::: __clobber_all); 105 } 106 107 SEC("tracepoint") 108 __description("bounded loop that jumps out rather than in") 109 __success jumps_out_rather_than_in(void)110__naked void jumps_out_rather_than_in(void) 111 { 112 asm volatile (" \ 113 r6 = 0; \ 114 l1_%=: r6 += 1; \ 115 if r6 > 10000 goto l0_%=; \ 116 call %[bpf_get_prandom_u32]; \ 117 goto l1_%=; \ 118 l0_%=: exit; \ 119 " : 120 : __imm(bpf_get_prandom_u32) 121 : __clobber_all); 122 } 123 124 SEC("tracepoint") 125 __description("infinite loop after a conditional jump") 126 __failure __msg("program is too large") loop_after_a_conditional_jump(void)127__naked void loop_after_a_conditional_jump(void) 128 { 129 asm volatile (" \ 130 r0 = 5; \ 131 if r0 < 4 goto l0_%=; \ 132 l1_%=: r0 += 1; \ 133 goto l1_%=; \ 134 l0_%=: exit; \ 135 " ::: __clobber_all); 136 } 137 138 SEC("tracepoint") 139 __description("bounded recursion") 140 __failure 141 /* verifier limitation in detecting max stack depth */ 142 __msg("the call stack of 8 frames is too deep !") bounded_recursion(void)143__naked void bounded_recursion(void) 144 { 145 asm volatile (" \ 146 r1 = 0; \ 147 call bounded_recursion__1; \ 148 exit; \ 149 " ::: __clobber_all); 150 } 151 152 static __naked __noinline __attribute__((used)) bounded_recursion__1(void)153void bounded_recursion__1(void) 154 { 155 asm volatile (" \ 156 r1 += 1; \ 157 r0 = r1; \ 158 if r1 < 4 goto l0_%=; \ 159 exit; \ 160 l0_%=: call bounded_recursion__1; \ 161 exit; \ 162 " ::: __clobber_all); 163 } 164 165 SEC("tracepoint") 166 __description("infinite loop in two jumps") 167 __failure __msg("loop detected") infinite_loop_in_two_jumps(void)168__naked void infinite_loop_in_two_jumps(void) 169 { 170 asm volatile (" \ 171 r0 = 0; \ 172 l1_%=: goto l0_%=; \ 173 l0_%=: if r0 < 4 goto l1_%=; \ 174 exit; \ 175 " ::: __clobber_all); 176 } 177 178 SEC("tracepoint") 179 __description("infinite loop: three-jump trick") 180 __failure __msg("loop detected") infinite_loop_three_jump_trick(void)181__naked void infinite_loop_three_jump_trick(void) 182 { 183 asm volatile (" \ 184 r0 = 0; \ 185 l2_%=: r0 += 1; \ 186 r0 &= 1; \ 187 if r0 < 2 goto l0_%=; \ 188 exit; \ 189 l0_%=: r0 += 1; \ 190 r0 &= 1; \ 191 if r0 < 2 goto l1_%=; \ 192 exit; \ 193 l1_%=: r0 += 1; \ 194 r0 &= 1; \ 195 if r0 < 2 goto l2_%=; \ 196 exit; \ 197 " ::: __clobber_all); 198 } 199 200 SEC("xdp") 201 __description("not-taken loop with back jump to 1st insn") 202 __success __retval(123) back_jump_to_1st_insn_1(void)203__naked void back_jump_to_1st_insn_1(void) 204 { 205 asm volatile (" \ 206 l0_%=: r0 = 123; \ 207 if r0 == 4 goto l0_%=; \ 208 exit; \ 209 " ::: __clobber_all); 210 } 211 212 SEC("xdp") 213 __description("taken loop with back jump to 1st insn") 214 __success __retval(55) back_jump_to_1st_insn_2(void)215__naked void back_jump_to_1st_insn_2(void) 216 { 217 asm volatile (" \ 218 r1 = 10; \ 219 r2 = 0; \ 220 call back_jump_to_1st_insn_2__1; \ 221 exit; \ 222 " ::: __clobber_all); 223 } 224 225 static __naked __noinline __attribute__((used)) back_jump_to_1st_insn_2__1(void)226void back_jump_to_1st_insn_2__1(void) 227 { 228 asm volatile (" \ 229 l0_%=: r2 += r1; \ 230 r1 -= 1; \ 231 if r1 != 0 goto l0_%=; \ 232 r0 = r2; \ 233 exit; \ 234 " ::: __clobber_all); 235 } 236 237 SEC("xdp") 238 __description("taken loop with back jump to 1st insn, 2") 239 __success __retval(55) jump_to_1st_insn_2(void)240__naked void jump_to_1st_insn_2(void) 241 { 242 asm volatile (" \ 243 r1 = 10; \ 244 r2 = 0; \ 245 call jump_to_1st_insn_2__1; \ 246 exit; \ 247 " ::: __clobber_all); 248 } 249 250 static __naked __noinline __attribute__((used)) jump_to_1st_insn_2__1(void)251void jump_to_1st_insn_2__1(void) 252 { 253 asm volatile (" \ 254 l0_%=: r2 += r1; \ 255 r1 -= 1; \ 256 if w1 != 0 goto l0_%=; \ 257 r0 = r2; \ 258 exit; \ 259 " ::: __clobber_all); 260 } 261 262 char _license[] SEC("license") = "GPL"; 263