1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Converted from tools/testing/selftests/bpf/verifier/bounds.c */ |
3 | |
4 | #include <linux/bpf.h> |
5 | #include <bpf/bpf_helpers.h> |
6 | #include "bpf_misc.h" |
7 | |
8 | struct { |
9 | __uint(type, BPF_MAP_TYPE_HASH); |
10 | __uint(max_entries, 1); |
11 | __type(key, long long); |
12 | __type(value, long long); |
13 | } map_hash_8b SEC(".maps" ); |
14 | |
15 | SEC("socket" ) |
16 | __description("subtraction bounds (map value) variant 1" ) |
17 | __failure __msg("R0 max value is outside of the allowed memory range" ) |
18 | __failure_unpriv |
19 | __naked void bounds_map_value_variant_1(void) |
20 | { |
21 | asm volatile (" \ |
22 | r1 = 0; \ |
23 | *(u64*)(r10 - 8) = r1; \ |
24 | r2 = r10; \ |
25 | r2 += -8; \ |
26 | r1 = %[map_hash_8b] ll; \ |
27 | call %[bpf_map_lookup_elem]; \ |
28 | if r0 == 0 goto l0_%=; \ |
29 | r1 = *(u8*)(r0 + 0); \ |
30 | if r1 > 0xff goto l0_%=; \ |
31 | r3 = *(u8*)(r0 + 1); \ |
32 | if r3 > 0xff goto l0_%=; \ |
33 | r1 -= r3; \ |
34 | r1 >>= 56; \ |
35 | r0 += r1; \ |
36 | r0 = *(u8*)(r0 + 0); \ |
37 | exit; \ |
38 | l0_%=: r0 = 0; \ |
39 | exit; \ |
40 | " : |
41 | : __imm(bpf_map_lookup_elem), |
42 | __imm_addr(map_hash_8b) |
43 | : __clobber_all); |
44 | } |
45 | |
46 | SEC("socket" ) |
47 | __description("subtraction bounds (map value) variant 2" ) |
48 | __failure |
49 | __msg("R0 min value is negative, either use unsigned index or do a if (index >=0) check." ) |
50 | __msg_unpriv("R1 has unknown scalar with mixed signed bounds" ) |
51 | __naked void bounds_map_value_variant_2(void) |
52 | { |
53 | asm volatile (" \ |
54 | r1 = 0; \ |
55 | *(u64*)(r10 - 8) = r1; \ |
56 | r2 = r10; \ |
57 | r2 += -8; \ |
58 | r1 = %[map_hash_8b] ll; \ |
59 | call %[bpf_map_lookup_elem]; \ |
60 | if r0 == 0 goto l0_%=; \ |
61 | r1 = *(u8*)(r0 + 0); \ |
62 | if r1 > 0xff goto l0_%=; \ |
63 | r3 = *(u8*)(r0 + 1); \ |
64 | if r3 > 0xff goto l0_%=; \ |
65 | r1 -= r3; \ |
66 | r0 += r1; \ |
67 | r0 = *(u8*)(r0 + 0); \ |
68 | exit; \ |
69 | l0_%=: r0 = 0; \ |
70 | exit; \ |
71 | " : |
72 | : __imm(bpf_map_lookup_elem), |
73 | __imm_addr(map_hash_8b) |
74 | : __clobber_all); |
75 | } |
76 | |
77 | SEC("socket" ) |
78 | __description("check subtraction on pointers for unpriv" ) |
79 | __success __failure_unpriv __msg_unpriv("R9 pointer -= pointer prohibited" ) |
80 | __retval(0) |
81 | __naked void subtraction_on_pointers_for_unpriv(void) |
82 | { |
83 | asm volatile (" \ |
84 | r0 = 0; \ |
85 | r1 = %[map_hash_8b] ll; \ |
86 | r2 = r10; \ |
87 | r2 += -8; \ |
88 | r6 = 9; \ |
89 | *(u64*)(r2 + 0) = r6; \ |
90 | call %[bpf_map_lookup_elem]; \ |
91 | r9 = r10; \ |
92 | r9 -= r0; \ |
93 | r1 = %[map_hash_8b] ll; \ |
94 | r2 = r10; \ |
95 | r2 += -8; \ |
96 | r6 = 0; \ |
97 | *(u64*)(r2 + 0) = r6; \ |
98 | call %[bpf_map_lookup_elem]; \ |
99 | if r0 != 0 goto l0_%=; \ |
100 | exit; \ |
101 | l0_%=: *(u64*)(r0 + 0) = r9; \ |
102 | r0 = 0; \ |
103 | exit; \ |
104 | " : |
105 | : __imm(bpf_map_lookup_elem), |
106 | __imm_addr(map_hash_8b) |
107 | : __clobber_all); |
108 | } |
109 | |
110 | SEC("socket" ) |
111 | __description("bounds check based on zero-extended MOV" ) |
112 | __success __success_unpriv __retval(0) |
113 | __naked void based_on_zero_extended_mov(void) |
114 | { |
115 | asm volatile (" \ |
116 | r1 = 0; \ |
117 | *(u64*)(r10 - 8) = r1; \ |
118 | r2 = r10; \ |
119 | r2 += -8; \ |
120 | r1 = %[map_hash_8b] ll; \ |
121 | call %[bpf_map_lookup_elem]; \ |
122 | if r0 == 0 goto l0_%=; \ |
123 | /* r2 = 0x0000'0000'ffff'ffff */ \ |
124 | w2 = 0xffffffff; \ |
125 | /* r2 = 0 */ \ |
126 | r2 >>= 32; \ |
127 | /* no-op */ \ |
128 | r0 += r2; \ |
129 | /* access at offset 0 */ \ |
130 | r0 = *(u8*)(r0 + 0); \ |
131 | l0_%=: /* exit */ \ |
132 | r0 = 0; \ |
133 | exit; \ |
134 | " : |
135 | : __imm(bpf_map_lookup_elem), |
136 | __imm_addr(map_hash_8b) |
137 | : __clobber_all); |
138 | } |
139 | |
140 | SEC("socket" ) |
141 | __description("bounds check based on sign-extended MOV. test1" ) |
142 | __failure __msg("map_value pointer and 4294967295" ) |
143 | __failure_unpriv |
144 | __naked void on_sign_extended_mov_test1(void) |
145 | { |
146 | asm volatile (" \ |
147 | r1 = 0; \ |
148 | *(u64*)(r10 - 8) = r1; \ |
149 | r2 = r10; \ |
150 | r2 += -8; \ |
151 | r1 = %[map_hash_8b] ll; \ |
152 | call %[bpf_map_lookup_elem]; \ |
153 | if r0 == 0 goto l0_%=; \ |
154 | /* r2 = 0xffff'ffff'ffff'ffff */ \ |
155 | r2 = 0xffffffff; \ |
156 | /* r2 = 0xffff'ffff */ \ |
157 | r2 >>= 32; \ |
158 | /* r0 = <oob pointer> */ \ |
159 | r0 += r2; \ |
160 | /* access to OOB pointer */ \ |
161 | r0 = *(u8*)(r0 + 0); \ |
162 | l0_%=: /* exit */ \ |
163 | r0 = 0; \ |
164 | exit; \ |
165 | " : |
166 | : __imm(bpf_map_lookup_elem), |
167 | __imm_addr(map_hash_8b) |
168 | : __clobber_all); |
169 | } |
170 | |
171 | SEC("socket" ) |
172 | __description("bounds check based on sign-extended MOV. test2" ) |
173 | __failure __msg("R0 min value is outside of the allowed memory range" ) |
174 | __failure_unpriv |
175 | __naked void on_sign_extended_mov_test2(void) |
176 | { |
177 | asm volatile (" \ |
178 | r1 = 0; \ |
179 | *(u64*)(r10 - 8) = r1; \ |
180 | r2 = r10; \ |
181 | r2 += -8; \ |
182 | r1 = %[map_hash_8b] ll; \ |
183 | call %[bpf_map_lookup_elem]; \ |
184 | if r0 == 0 goto l0_%=; \ |
185 | /* r2 = 0xffff'ffff'ffff'ffff */ \ |
186 | r2 = 0xffffffff; \ |
187 | /* r2 = 0xfff'ffff */ \ |
188 | r2 >>= 36; \ |
189 | /* r0 = <oob pointer> */ \ |
190 | r0 += r2; \ |
191 | /* access to OOB pointer */ \ |
192 | r0 = *(u8*)(r0 + 0); \ |
193 | l0_%=: /* exit */ \ |
194 | r0 = 0; \ |
195 | exit; \ |
196 | " : |
197 | : __imm(bpf_map_lookup_elem), |
198 | __imm_addr(map_hash_8b) |
199 | : __clobber_all); |
200 | } |
201 | |
202 | SEC("tc" ) |
203 | __description("bounds check based on reg_off + var_off + insn_off. test1" ) |
204 | __failure __msg("value_size=8 off=1073741825" ) |
205 | __naked void var_off_insn_off_test1(void) |
206 | { |
207 | asm volatile (" \ |
208 | r6 = *(u32*)(r1 + %[__sk_buff_mark]); \ |
209 | r1 = 0; \ |
210 | *(u64*)(r10 - 8) = r1; \ |
211 | r2 = r10; \ |
212 | r2 += -8; \ |
213 | r1 = %[map_hash_8b] ll; \ |
214 | call %[bpf_map_lookup_elem]; \ |
215 | if r0 == 0 goto l0_%=; \ |
216 | r6 &= 1; \ |
217 | r6 += %[__imm_0]; \ |
218 | r0 += r6; \ |
219 | r0 += %[__imm_0]; \ |
220 | l0_%=: r0 = *(u8*)(r0 + 3); \ |
221 | r0 = 0; \ |
222 | exit; \ |
223 | " : |
224 | : __imm(bpf_map_lookup_elem), |
225 | __imm_addr(map_hash_8b), |
226 | __imm_const(__imm_0, (1 << 29) - 1), |
227 | __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)) |
228 | : __clobber_all); |
229 | } |
230 | |
231 | SEC("tc" ) |
232 | __description("bounds check based on reg_off + var_off + insn_off. test2" ) |
233 | __failure __msg("value 1073741823" ) |
234 | __naked void var_off_insn_off_test2(void) |
235 | { |
236 | asm volatile (" \ |
237 | r6 = *(u32*)(r1 + %[__sk_buff_mark]); \ |
238 | r1 = 0; \ |
239 | *(u64*)(r10 - 8) = r1; \ |
240 | r2 = r10; \ |
241 | r2 += -8; \ |
242 | r1 = %[map_hash_8b] ll; \ |
243 | call %[bpf_map_lookup_elem]; \ |
244 | if r0 == 0 goto l0_%=; \ |
245 | r6 &= 1; \ |
246 | r6 += %[__imm_0]; \ |
247 | r0 += r6; \ |
248 | r0 += %[__imm_1]; \ |
249 | l0_%=: r0 = *(u8*)(r0 + 3); \ |
250 | r0 = 0; \ |
251 | exit; \ |
252 | " : |
253 | : __imm(bpf_map_lookup_elem), |
254 | __imm_addr(map_hash_8b), |
255 | __imm_const(__imm_0, (1 << 30) - 1), |
256 | __imm_const(__imm_1, (1 << 29) - 1), |
257 | __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)) |
258 | : __clobber_all); |
259 | } |
260 | |
261 | SEC("socket" ) |
262 | __description("bounds check after truncation of non-boundary-crossing range" ) |
263 | __success __success_unpriv __retval(0) |
264 | __naked void of_non_boundary_crossing_range(void) |
265 | { |
266 | asm volatile (" \ |
267 | r1 = 0; \ |
268 | *(u64*)(r10 - 8) = r1; \ |
269 | r2 = r10; \ |
270 | r2 += -8; \ |
271 | r1 = %[map_hash_8b] ll; \ |
272 | call %[bpf_map_lookup_elem]; \ |
273 | if r0 == 0 goto l0_%=; \ |
274 | /* r1 = [0x00, 0xff] */ \ |
275 | r1 = *(u8*)(r0 + 0); \ |
276 | r2 = 1; \ |
277 | /* r2 = 0x10'0000'0000 */ \ |
278 | r2 <<= 36; \ |
279 | /* r1 = [0x10'0000'0000, 0x10'0000'00ff] */ \ |
280 | r1 += r2; \ |
281 | /* r1 = [0x10'7fff'ffff, 0x10'8000'00fe] */ \ |
282 | r1 += 0x7fffffff; \ |
283 | /* r1 = [0x00, 0xff] */ \ |
284 | w1 -= 0x7fffffff; \ |
285 | /* r1 = 0 */ \ |
286 | r1 >>= 8; \ |
287 | /* no-op */ \ |
288 | r0 += r1; \ |
289 | /* access at offset 0 */ \ |
290 | r0 = *(u8*)(r0 + 0); \ |
291 | l0_%=: /* exit */ \ |
292 | r0 = 0; \ |
293 | exit; \ |
294 | " : |
295 | : __imm(bpf_map_lookup_elem), |
296 | __imm_addr(map_hash_8b) |
297 | : __clobber_all); |
298 | } |
299 | |
300 | SEC("socket" ) |
301 | __description("bounds check after truncation of boundary-crossing range (1)" ) |
302 | __failure |
303 | /* not actually fully unbounded, but the bound is very high */ |
304 | __msg("value -4294967168 makes map_value pointer be out of bounds" ) |
305 | __failure_unpriv |
306 | __naked void of_boundary_crossing_range_1(void) |
307 | { |
308 | asm volatile (" \ |
309 | r1 = 0; \ |
310 | *(u64*)(r10 - 8) = r1; \ |
311 | r2 = r10; \ |
312 | r2 += -8; \ |
313 | r1 = %[map_hash_8b] ll; \ |
314 | call %[bpf_map_lookup_elem]; \ |
315 | if r0 == 0 goto l0_%=; \ |
316 | /* r1 = [0x00, 0xff] */ \ |
317 | r1 = *(u8*)(r0 + 0); \ |
318 | r1 += %[__imm_0]; \ |
319 | /* r1 = [0xffff'ff80, 0x1'0000'007f] */ \ |
320 | r1 += %[__imm_0]; \ |
321 | /* r1 = [0xffff'ff80, 0xffff'ffff] or \ |
322 | * [0x0000'0000, 0x0000'007f] \ |
323 | */ \ |
324 | w1 += 0; \ |
325 | r1 -= %[__imm_0]; \ |
326 | /* r1 = [0x00, 0xff] or \ |
327 | * [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff]\ |
328 | */ \ |
329 | r1 -= %[__imm_0]; \ |
330 | /* error on OOB pointer computation */ \ |
331 | r0 += r1; \ |
332 | /* exit */ \ |
333 | r0 = 0; \ |
334 | l0_%=: exit; \ |
335 | " : |
336 | : __imm(bpf_map_lookup_elem), |
337 | __imm_addr(map_hash_8b), |
338 | __imm_const(__imm_0, 0xffffff80 >> 1) |
339 | : __clobber_all); |
340 | } |
341 | |
342 | SEC("socket" ) |
343 | __description("bounds check after truncation of boundary-crossing range (2)" ) |
344 | __failure __msg("value -4294967168 makes map_value pointer be out of bounds" ) |
345 | __failure_unpriv |
346 | __naked void of_boundary_crossing_range_2(void) |
347 | { |
348 | asm volatile (" \ |
349 | r1 = 0; \ |
350 | *(u64*)(r10 - 8) = r1; \ |
351 | r2 = r10; \ |
352 | r2 += -8; \ |
353 | r1 = %[map_hash_8b] ll; \ |
354 | call %[bpf_map_lookup_elem]; \ |
355 | if r0 == 0 goto l0_%=; \ |
356 | /* r1 = [0x00, 0xff] */ \ |
357 | r1 = *(u8*)(r0 + 0); \ |
358 | r1 += %[__imm_0]; \ |
359 | /* r1 = [0xffff'ff80, 0x1'0000'007f] */ \ |
360 | r1 += %[__imm_0]; \ |
361 | /* r1 = [0xffff'ff80, 0xffff'ffff] or \ |
362 | * [0x0000'0000, 0x0000'007f] \ |
363 | * difference to previous test: truncation via MOV32\ |
364 | * instead of ALU32. \ |
365 | */ \ |
366 | w1 = w1; \ |
367 | r1 -= %[__imm_0]; \ |
368 | /* r1 = [0x00, 0xff] or \ |
369 | * [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff]\ |
370 | */ \ |
371 | r1 -= %[__imm_0]; \ |
372 | /* error on OOB pointer computation */ \ |
373 | r0 += r1; \ |
374 | /* exit */ \ |
375 | r0 = 0; \ |
376 | l0_%=: exit; \ |
377 | " : |
378 | : __imm(bpf_map_lookup_elem), |
379 | __imm_addr(map_hash_8b), |
380 | __imm_const(__imm_0, 0xffffff80 >> 1) |
381 | : __clobber_all); |
382 | } |
383 | |
384 | SEC("socket" ) |
385 | __description("bounds check after wrapping 32-bit addition" ) |
386 | __success __success_unpriv __retval(0) |
387 | __naked void after_wrapping_32_bit_addition(void) |
388 | { |
389 | asm volatile (" \ |
390 | r1 = 0; \ |
391 | *(u64*)(r10 - 8) = r1; \ |
392 | r2 = r10; \ |
393 | r2 += -8; \ |
394 | r1 = %[map_hash_8b] ll; \ |
395 | call %[bpf_map_lookup_elem]; \ |
396 | if r0 == 0 goto l0_%=; \ |
397 | /* r1 = 0x7fff'ffff */ \ |
398 | r1 = 0x7fffffff; \ |
399 | /* r1 = 0xffff'fffe */ \ |
400 | r1 += 0x7fffffff; \ |
401 | /* r1 = 0 */ \ |
402 | w1 += 2; \ |
403 | /* no-op */ \ |
404 | r0 += r1; \ |
405 | /* access at offset 0 */ \ |
406 | r0 = *(u8*)(r0 + 0); \ |
407 | l0_%=: /* exit */ \ |
408 | r0 = 0; \ |
409 | exit; \ |
410 | " : |
411 | : __imm(bpf_map_lookup_elem), |
412 | __imm_addr(map_hash_8b) |
413 | : __clobber_all); |
414 | } |
415 | |
416 | SEC("socket" ) |
417 | __description("bounds check after shift with oversized count operand" ) |
418 | __failure __msg("R0 max value is outside of the allowed memory range" ) |
419 | __failure_unpriv |
420 | __naked void shift_with_oversized_count_operand(void) |
421 | { |
422 | asm volatile (" \ |
423 | r1 = 0; \ |
424 | *(u64*)(r10 - 8) = r1; \ |
425 | r2 = r10; \ |
426 | r2 += -8; \ |
427 | r1 = %[map_hash_8b] ll; \ |
428 | call %[bpf_map_lookup_elem]; \ |
429 | if r0 == 0 goto l0_%=; \ |
430 | r2 = 32; \ |
431 | r1 = 1; \ |
432 | /* r1 = (u32)1 << (u32)32 = ? */ \ |
433 | w1 <<= w2; \ |
434 | /* r1 = [0x0000, 0xffff] */ \ |
435 | r1 &= 0xffff; \ |
436 | /* computes unknown pointer, potentially OOB */ \ |
437 | r0 += r1; \ |
438 | /* potentially OOB access */ \ |
439 | r0 = *(u8*)(r0 + 0); \ |
440 | l0_%=: /* exit */ \ |
441 | r0 = 0; \ |
442 | exit; \ |
443 | " : |
444 | : __imm(bpf_map_lookup_elem), |
445 | __imm_addr(map_hash_8b) |
446 | : __clobber_all); |
447 | } |
448 | |
449 | SEC("socket" ) |
450 | __description("bounds check after right shift of maybe-negative number" ) |
451 | __failure __msg("R0 unbounded memory access" ) |
452 | __failure_unpriv |
453 | __naked void shift_of_maybe_negative_number(void) |
454 | { |
455 | asm volatile (" \ |
456 | r1 = 0; \ |
457 | *(u64*)(r10 - 8) = r1; \ |
458 | r2 = r10; \ |
459 | r2 += -8; \ |
460 | r1 = %[map_hash_8b] ll; \ |
461 | call %[bpf_map_lookup_elem]; \ |
462 | if r0 == 0 goto l0_%=; \ |
463 | /* r1 = [0x00, 0xff] */ \ |
464 | r1 = *(u8*)(r0 + 0); \ |
465 | /* r1 = [-0x01, 0xfe] */ \ |
466 | r1 -= 1; \ |
467 | /* r1 = 0 or 0xff'ffff'ffff'ffff */ \ |
468 | r1 >>= 8; \ |
469 | /* r1 = 0 or 0xffff'ffff'ffff */ \ |
470 | r1 >>= 8; \ |
471 | /* computes unknown pointer, potentially OOB */ \ |
472 | r0 += r1; \ |
473 | /* potentially OOB access */ \ |
474 | r0 = *(u8*)(r0 + 0); \ |
475 | l0_%=: /* exit */ \ |
476 | r0 = 0; \ |
477 | exit; \ |
478 | " : |
479 | : __imm(bpf_map_lookup_elem), |
480 | __imm_addr(map_hash_8b) |
481 | : __clobber_all); |
482 | } |
483 | |
484 | SEC("socket" ) |
485 | __description("bounds check after 32-bit right shift with 64-bit input" ) |
486 | __failure __msg("math between map_value pointer and 4294967294 is not allowed" ) |
487 | __failure_unpriv |
488 | __naked void shift_with_64_bit_input(void) |
489 | { |
490 | asm volatile (" \ |
491 | r1 = 0; \ |
492 | *(u64*)(r10 - 8) = r1; \ |
493 | r2 = r10; \ |
494 | r2 += -8; \ |
495 | r1 = %[map_hash_8b] ll; \ |
496 | call %[bpf_map_lookup_elem]; \ |
497 | if r0 == 0 goto l0_%=; \ |
498 | r1 = 2; \ |
499 | /* r1 = 1<<32 */ \ |
500 | r1 <<= 31; \ |
501 | /* r1 = 0 (NOT 2!) */ \ |
502 | w1 >>= 31; \ |
503 | /* r1 = 0xffff'fffe (NOT 0!) */ \ |
504 | w1 -= 2; \ |
505 | /* error on computing OOB pointer */ \ |
506 | r0 += r1; \ |
507 | /* exit */ \ |
508 | r0 = 0; \ |
509 | l0_%=: exit; \ |
510 | " : |
511 | : __imm(bpf_map_lookup_elem), |
512 | __imm_addr(map_hash_8b) |
513 | : __clobber_all); |
514 | } |
515 | |
516 | SEC("socket" ) |
517 | __description("bounds check map access with off+size signed 32bit overflow. test1" ) |
518 | __failure __msg("map_value pointer and 2147483646" ) |
519 | __failure_unpriv |
520 | __naked void size_signed_32bit_overflow_test1(void) |
521 | { |
522 | asm volatile (" \ |
523 | r1 = 0; \ |
524 | *(u64*)(r10 - 8) = r1; \ |
525 | r2 = r10; \ |
526 | r2 += -8; \ |
527 | r1 = %[map_hash_8b] ll; \ |
528 | call %[bpf_map_lookup_elem]; \ |
529 | if r0 != 0 goto l0_%=; \ |
530 | exit; \ |
531 | l0_%=: r0 += 0x7ffffffe; \ |
532 | r0 = *(u64*)(r0 + 0); \ |
533 | goto l1_%=; \ |
534 | l1_%=: exit; \ |
535 | " : |
536 | : __imm(bpf_map_lookup_elem), |
537 | __imm_addr(map_hash_8b) |
538 | : __clobber_all); |
539 | } |
540 | |
541 | SEC("socket" ) |
542 | __description("bounds check map access with off+size signed 32bit overflow. test2" ) |
543 | __failure __msg("pointer offset 1073741822" ) |
544 | __msg_unpriv("R0 pointer arithmetic of map value goes out of range" ) |
545 | __naked void size_signed_32bit_overflow_test2(void) |
546 | { |
547 | asm volatile (" \ |
548 | r1 = 0; \ |
549 | *(u64*)(r10 - 8) = r1; \ |
550 | r2 = r10; \ |
551 | r2 += -8; \ |
552 | r1 = %[map_hash_8b] ll; \ |
553 | call %[bpf_map_lookup_elem]; \ |
554 | if r0 != 0 goto l0_%=; \ |
555 | exit; \ |
556 | l0_%=: r0 += 0x1fffffff; \ |
557 | r0 += 0x1fffffff; \ |
558 | r0 += 0x1fffffff; \ |
559 | r0 = *(u64*)(r0 + 0); \ |
560 | goto l1_%=; \ |
561 | l1_%=: exit; \ |
562 | " : |
563 | : __imm(bpf_map_lookup_elem), |
564 | __imm_addr(map_hash_8b) |
565 | : __clobber_all); |
566 | } |
567 | |
568 | SEC("socket" ) |
569 | __description("bounds check map access with off+size signed 32bit overflow. test3" ) |
570 | __failure __msg("pointer offset -1073741822" ) |
571 | __msg_unpriv("R0 pointer arithmetic of map value goes out of range" ) |
572 | __naked void size_signed_32bit_overflow_test3(void) |
573 | { |
574 | asm volatile (" \ |
575 | r1 = 0; \ |
576 | *(u64*)(r10 - 8) = r1; \ |
577 | r2 = r10; \ |
578 | r2 += -8; \ |
579 | r1 = %[map_hash_8b] ll; \ |
580 | call %[bpf_map_lookup_elem]; \ |
581 | if r0 != 0 goto l0_%=; \ |
582 | exit; \ |
583 | l0_%=: r0 -= 0x1fffffff; \ |
584 | r0 -= 0x1fffffff; \ |
585 | r0 = *(u64*)(r0 + 2); \ |
586 | goto l1_%=; \ |
587 | l1_%=: exit; \ |
588 | " : |
589 | : __imm(bpf_map_lookup_elem), |
590 | __imm_addr(map_hash_8b) |
591 | : __clobber_all); |
592 | } |
593 | |
594 | SEC("socket" ) |
595 | __description("bounds check map access with off+size signed 32bit overflow. test4" ) |
596 | __failure __msg("map_value pointer and 1000000000000" ) |
597 | __failure_unpriv |
598 | __naked void size_signed_32bit_overflow_test4(void) |
599 | { |
600 | asm volatile (" \ |
601 | r1 = 0; \ |
602 | *(u64*)(r10 - 8) = r1; \ |
603 | r2 = r10; \ |
604 | r2 += -8; \ |
605 | r1 = %[map_hash_8b] ll; \ |
606 | call %[bpf_map_lookup_elem]; \ |
607 | if r0 != 0 goto l0_%=; \ |
608 | exit; \ |
609 | l0_%=: r1 = 1000000; \ |
610 | r1 *= 1000000; \ |
611 | r0 += r1; \ |
612 | r0 = *(u64*)(r0 + 2); \ |
613 | goto l1_%=; \ |
614 | l1_%=: exit; \ |
615 | " : |
616 | : __imm(bpf_map_lookup_elem), |
617 | __imm_addr(map_hash_8b) |
618 | : __clobber_all); |
619 | } |
620 | |
621 | SEC("socket" ) |
622 | __description("bounds check mixed 32bit and 64bit arithmetic. test1" ) |
623 | __success __failure_unpriv __msg_unpriv("R0 invalid mem access 'scalar'" ) |
624 | __retval(0) |
625 | __naked void _32bit_and_64bit_arithmetic_test1(void) |
626 | { |
627 | asm volatile (" \ |
628 | r0 = 0; \ |
629 | r1 = -1; \ |
630 | r1 <<= 32; \ |
631 | r1 += 1; \ |
632 | /* r1 = 0xffffFFFF00000001 */ \ |
633 | if w1 > 1 goto l0_%=; \ |
634 | /* check ALU64 op keeps 32bit bounds */ \ |
635 | r1 += 1; \ |
636 | if w1 > 2 goto l0_%=; \ |
637 | goto l1_%=; \ |
638 | l0_%=: /* invalid ldx if bounds are lost above */ \ |
639 | r0 = *(u64*)(r0 - 1); \ |
640 | l1_%=: exit; \ |
641 | " ::: __clobber_all); |
642 | } |
643 | |
644 | SEC("socket" ) |
645 | __description("bounds check mixed 32bit and 64bit arithmetic. test2" ) |
646 | __success __failure_unpriv __msg_unpriv("R0 invalid mem access 'scalar'" ) |
647 | __retval(0) |
648 | __naked void _32bit_and_64bit_arithmetic_test2(void) |
649 | { |
650 | asm volatile (" \ |
651 | r0 = 0; \ |
652 | r1 = -1; \ |
653 | r1 <<= 32; \ |
654 | r1 += 1; \ |
655 | /* r1 = 0xffffFFFF00000001 */ \ |
656 | r2 = 3; \ |
657 | /* r1 = 0x2 */ \ |
658 | w1 += 1; \ |
659 | /* check ALU32 op zero extends 64bit bounds */ \ |
660 | if r1 > r2 goto l0_%=; \ |
661 | goto l1_%=; \ |
662 | l0_%=: /* invalid ldx if bounds are lost above */ \ |
663 | r0 = *(u64*)(r0 - 1); \ |
664 | l1_%=: exit; \ |
665 | " ::: __clobber_all); |
666 | } |
667 | |
668 | SEC("tc" ) |
669 | __description("assigning 32bit bounds to 64bit for wA = 0, wB = wA" ) |
670 | __success __retval(0) __flag(BPF_F_ANY_ALIGNMENT) |
671 | __naked void for_wa_0_wb_wa(void) |
672 | { |
673 | asm volatile (" \ |
674 | r8 = *(u32*)(r1 + %[__sk_buff_data_end]); \ |
675 | r7 = *(u32*)(r1 + %[__sk_buff_data]); \ |
676 | w9 = 0; \ |
677 | w2 = w9; \ |
678 | r6 = r7; \ |
679 | r6 += r2; \ |
680 | r3 = r6; \ |
681 | r3 += 8; \ |
682 | if r3 > r8 goto l0_%=; \ |
683 | r5 = *(u32*)(r6 + 0); \ |
684 | l0_%=: r0 = 0; \ |
685 | exit; \ |
686 | " : |
687 | : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)), |
688 | __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end)) |
689 | : __clobber_all); |
690 | } |
691 | |
692 | SEC("socket" ) |
693 | __description("bounds check for reg = 0, reg xor 1" ) |
694 | __success __failure_unpriv |
695 | __msg_unpriv("R0 min value is outside of the allowed memory range" ) |
696 | __retval(0) |
697 | __naked void reg_0_reg_xor_1(void) |
698 | { |
699 | asm volatile (" \ |
700 | r1 = 0; \ |
701 | *(u64*)(r10 - 8) = r1; \ |
702 | r2 = r10; \ |
703 | r2 += -8; \ |
704 | r1 = %[map_hash_8b] ll; \ |
705 | call %[bpf_map_lookup_elem]; \ |
706 | if r0 != 0 goto l0_%=; \ |
707 | exit; \ |
708 | l0_%=: r1 = 0; \ |
709 | r1 ^= 1; \ |
710 | if r1 != 0 goto l1_%=; \ |
711 | r0 = *(u64*)(r0 + 8); \ |
712 | l1_%=: r0 = 0; \ |
713 | exit; \ |
714 | " : |
715 | : __imm(bpf_map_lookup_elem), |
716 | __imm_addr(map_hash_8b) |
717 | : __clobber_all); |
718 | } |
719 | |
720 | SEC("socket" ) |
721 | __description("bounds check for reg32 = 0, reg32 xor 1" ) |
722 | __success __failure_unpriv |
723 | __msg_unpriv("R0 min value is outside of the allowed memory range" ) |
724 | __retval(0) |
725 | __naked void reg32_0_reg32_xor_1(void) |
726 | { |
727 | asm volatile (" \ |
728 | r1 = 0; \ |
729 | *(u64*)(r10 - 8) = r1; \ |
730 | r2 = r10; \ |
731 | r2 += -8; \ |
732 | r1 = %[map_hash_8b] ll; \ |
733 | call %[bpf_map_lookup_elem]; \ |
734 | if r0 != 0 goto l0_%=; \ |
735 | exit; \ |
736 | l0_%=: w1 = 0; \ |
737 | w1 ^= 1; \ |
738 | if w1 != 0 goto l1_%=; \ |
739 | r0 = *(u64*)(r0 + 8); \ |
740 | l1_%=: r0 = 0; \ |
741 | exit; \ |
742 | " : |
743 | : __imm(bpf_map_lookup_elem), |
744 | __imm_addr(map_hash_8b) |
745 | : __clobber_all); |
746 | } |
747 | |
748 | SEC("socket" ) |
749 | __description("bounds check for reg = 2, reg xor 3" ) |
750 | __success __failure_unpriv |
751 | __msg_unpriv("R0 min value is outside of the allowed memory range" ) |
752 | __retval(0) |
753 | __naked void reg_2_reg_xor_3(void) |
754 | { |
755 | asm volatile (" \ |
756 | r1 = 0; \ |
757 | *(u64*)(r10 - 8) = r1; \ |
758 | r2 = r10; \ |
759 | r2 += -8; \ |
760 | r1 = %[map_hash_8b] ll; \ |
761 | call %[bpf_map_lookup_elem]; \ |
762 | if r0 != 0 goto l0_%=; \ |
763 | exit; \ |
764 | l0_%=: r1 = 2; \ |
765 | r1 ^= 3; \ |
766 | if r1 > 0 goto l1_%=; \ |
767 | r0 = *(u64*)(r0 + 8); \ |
768 | l1_%=: r0 = 0; \ |
769 | exit; \ |
770 | " : |
771 | : __imm(bpf_map_lookup_elem), |
772 | __imm_addr(map_hash_8b) |
773 | : __clobber_all); |
774 | } |
775 | |
776 | SEC("socket" ) |
777 | __description("bounds check for reg = any, reg xor 3" ) |
778 | __failure __msg("invalid access to map value" ) |
779 | __msg_unpriv("invalid access to map value" ) |
780 | __naked void reg_any_reg_xor_3(void) |
781 | { |
782 | asm volatile (" \ |
783 | r1 = 0; \ |
784 | *(u64*)(r10 - 8) = r1; \ |
785 | r2 = r10; \ |
786 | r2 += -8; \ |
787 | r1 = %[map_hash_8b] ll; \ |
788 | call %[bpf_map_lookup_elem]; \ |
789 | if r0 != 0 goto l0_%=; \ |
790 | exit; \ |
791 | l0_%=: r1 = *(u64*)(r0 + 0); \ |
792 | r1 ^= 3; \ |
793 | if r1 != 0 goto l1_%=; \ |
794 | r0 = *(u64*)(r0 + 8); \ |
795 | l1_%=: r0 = 0; \ |
796 | exit; \ |
797 | " : |
798 | : __imm(bpf_map_lookup_elem), |
799 | __imm_addr(map_hash_8b) |
800 | : __clobber_all); |
801 | } |
802 | |
803 | SEC("socket" ) |
804 | __description("bounds check for reg32 = any, reg32 xor 3" ) |
805 | __failure __msg("invalid access to map value" ) |
806 | __msg_unpriv("invalid access to map value" ) |
807 | __naked void reg32_any_reg32_xor_3(void) |
808 | { |
809 | asm volatile (" \ |
810 | r1 = 0; \ |
811 | *(u64*)(r10 - 8) = r1; \ |
812 | r2 = r10; \ |
813 | r2 += -8; \ |
814 | r1 = %[map_hash_8b] ll; \ |
815 | call %[bpf_map_lookup_elem]; \ |
816 | if r0 != 0 goto l0_%=; \ |
817 | exit; \ |
818 | l0_%=: r1 = *(u64*)(r0 + 0); \ |
819 | w1 ^= 3; \ |
820 | if w1 != 0 goto l1_%=; \ |
821 | r0 = *(u64*)(r0 + 8); \ |
822 | l1_%=: r0 = 0; \ |
823 | exit; \ |
824 | " : |
825 | : __imm(bpf_map_lookup_elem), |
826 | __imm_addr(map_hash_8b) |
827 | : __clobber_all); |
828 | } |
829 | |
830 | SEC("socket" ) |
831 | __description("bounds check for reg > 0, reg xor 3" ) |
832 | __success __failure_unpriv |
833 | __msg_unpriv("R0 min value is outside of the allowed memory range" ) |
834 | __retval(0) |
835 | __naked void reg_0_reg_xor_3(void) |
836 | { |
837 | asm volatile (" \ |
838 | r1 = 0; \ |
839 | *(u64*)(r10 - 8) = r1; \ |
840 | r2 = r10; \ |
841 | r2 += -8; \ |
842 | r1 = %[map_hash_8b] ll; \ |
843 | call %[bpf_map_lookup_elem]; \ |
844 | if r0 != 0 goto l0_%=; \ |
845 | exit; \ |
846 | l0_%=: r1 = *(u64*)(r0 + 0); \ |
847 | if r1 <= 0 goto l1_%=; \ |
848 | r1 ^= 3; \ |
849 | if r1 >= 0 goto l1_%=; \ |
850 | r0 = *(u64*)(r0 + 8); \ |
851 | l1_%=: r0 = 0; \ |
852 | exit; \ |
853 | " : |
854 | : __imm(bpf_map_lookup_elem), |
855 | __imm_addr(map_hash_8b) |
856 | : __clobber_all); |
857 | } |
858 | |
859 | SEC("socket" ) |
860 | __description("bounds check for reg32 > 0, reg32 xor 3" ) |
861 | __success __failure_unpriv |
862 | __msg_unpriv("R0 min value is outside of the allowed memory range" ) |
863 | __retval(0) |
864 | __naked void reg32_0_reg32_xor_3(void) |
865 | { |
866 | asm volatile (" \ |
867 | r1 = 0; \ |
868 | *(u64*)(r10 - 8) = r1; \ |
869 | r2 = r10; \ |
870 | r2 += -8; \ |
871 | r1 = %[map_hash_8b] ll; \ |
872 | call %[bpf_map_lookup_elem]; \ |
873 | if r0 != 0 goto l0_%=; \ |
874 | exit; \ |
875 | l0_%=: r1 = *(u64*)(r0 + 0); \ |
876 | if w1 <= 0 goto l1_%=; \ |
877 | w1 ^= 3; \ |
878 | if w1 >= 0 goto l1_%=; \ |
879 | r0 = *(u64*)(r0 + 8); \ |
880 | l1_%=: r0 = 0; \ |
881 | exit; \ |
882 | " : |
883 | : __imm(bpf_map_lookup_elem), |
884 | __imm_addr(map_hash_8b) |
885 | : __clobber_all); |
886 | } |
887 | |
888 | SEC("socket" ) |
889 | __description("bounds checks after 32-bit truncation. test 1" ) |
890 | __success __failure_unpriv __msg_unpriv("R0 leaks addr" ) |
891 | __retval(0) |
892 | __naked void _32_bit_truncation_test_1(void) |
893 | { |
894 | asm volatile (" \ |
895 | r1 = 0; \ |
896 | *(u64*)(r10 - 8) = r1; \ |
897 | r2 = r10; \ |
898 | r2 += -8; \ |
899 | r1 = %[map_hash_8b] ll; \ |
900 | call %[bpf_map_lookup_elem]; \ |
901 | if r0 == 0 goto l0_%=; \ |
902 | r1 = *(u32*)(r0 + 0); \ |
903 | /* This used to reduce the max bound to 0x7fffffff */\ |
904 | if r1 == 0 goto l1_%=; \ |
905 | if r1 > 0x7fffffff goto l0_%=; \ |
906 | l1_%=: r0 = 0; \ |
907 | l0_%=: exit; \ |
908 | " : |
909 | : __imm(bpf_map_lookup_elem), |
910 | __imm_addr(map_hash_8b) |
911 | : __clobber_all); |
912 | } |
913 | |
914 | SEC("socket" ) |
915 | __description("bounds checks after 32-bit truncation. test 2" ) |
916 | __success __failure_unpriv __msg_unpriv("R0 leaks addr" ) |
917 | __retval(0) |
918 | __naked void _32_bit_truncation_test_2(void) |
919 | { |
920 | asm volatile (" \ |
921 | r1 = 0; \ |
922 | *(u64*)(r10 - 8) = r1; \ |
923 | r2 = r10; \ |
924 | r2 += -8; \ |
925 | r1 = %[map_hash_8b] ll; \ |
926 | call %[bpf_map_lookup_elem]; \ |
927 | if r0 == 0 goto l0_%=; \ |
928 | r1 = *(u32*)(r0 + 0); \ |
929 | if r1 s< 1 goto l1_%=; \ |
930 | if w1 s< 0 goto l0_%=; \ |
931 | l1_%=: r0 = 0; \ |
932 | l0_%=: exit; \ |
933 | " : |
934 | : __imm(bpf_map_lookup_elem), |
935 | __imm_addr(map_hash_8b) |
936 | : __clobber_all); |
937 | } |
938 | |
939 | SEC("xdp" ) |
940 | __description("bound check with JMP_JLT for crossing 64-bit signed boundary" ) |
941 | __success __retval(0) |
942 | __naked void crossing_64_bit_signed_boundary_1(void) |
943 | { |
944 | asm volatile (" \ |
945 | r2 = *(u32*)(r1 + %[xdp_md_data]); \ |
946 | r3 = *(u32*)(r1 + %[xdp_md_data_end]); \ |
947 | r1 = r2; \ |
948 | r1 += 1; \ |
949 | if r1 > r3 goto l0_%=; \ |
950 | r1 = *(u8*)(r2 + 0); \ |
951 | r0 = 0x7fffffffffffff10 ll; \ |
952 | r1 += r0; \ |
953 | r0 = 0x8000000000000000 ll; \ |
954 | l1_%=: r0 += 1; \ |
955 | /* r1 unsigned range is [0x7fffffffffffff10, 0x800000000000000f] */\ |
956 | if r0 < r1 goto l1_%=; \ |
957 | l0_%=: r0 = 0; \ |
958 | exit; \ |
959 | " : |
960 | : __imm_const(xdp_md_data, offsetof(struct xdp_md, data)), |
961 | __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end)) |
962 | : __clobber_all); |
963 | } |
964 | |
965 | SEC("xdp" ) |
966 | __description("bound check with JMP_JSLT for crossing 64-bit signed boundary" ) |
967 | __success __retval(0) |
968 | __flag(!BPF_F_TEST_REG_INVARIANTS) /* known invariants violation */ |
969 | __naked void crossing_64_bit_signed_boundary_2(void) |
970 | { |
971 | asm volatile (" \ |
972 | r2 = *(u32*)(r1 + %[xdp_md_data]); \ |
973 | r3 = *(u32*)(r1 + %[xdp_md_data_end]); \ |
974 | r1 = r2; \ |
975 | r1 += 1; \ |
976 | if r1 > r3 goto l0_%=; \ |
977 | r1 = *(u8*)(r2 + 0); \ |
978 | r0 = 0x7fffffffffffff10 ll; \ |
979 | r1 += r0; \ |
980 | r2 = 0x8000000000000fff ll; \ |
981 | r0 = 0x8000000000000000 ll; \ |
982 | l1_%=: r0 += 1; \ |
983 | if r0 s> r2 goto l0_%=; \ |
984 | /* r1 signed range is [S64_MIN, S64_MAX] */ \ |
985 | if r0 s< r1 goto l1_%=; \ |
986 | r0 = 1; \ |
987 | exit; \ |
988 | l0_%=: r0 = 0; \ |
989 | exit; \ |
990 | " : |
991 | : __imm_const(xdp_md_data, offsetof(struct xdp_md, data)), |
992 | __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end)) |
993 | : __clobber_all); |
994 | } |
995 | |
996 | SEC("xdp" ) |
997 | __description("bound check for loop upper bound greater than U32_MAX" ) |
998 | __success __retval(0) |
999 | __naked void bound_greater_than_u32_max(void) |
1000 | { |
1001 | asm volatile (" \ |
1002 | r2 = *(u32*)(r1 + %[xdp_md_data]); \ |
1003 | r3 = *(u32*)(r1 + %[xdp_md_data_end]); \ |
1004 | r1 = r2; \ |
1005 | r1 += 1; \ |
1006 | if r1 > r3 goto l0_%=; \ |
1007 | r1 = *(u8*)(r2 + 0); \ |
1008 | r0 = 0x100000000 ll; \ |
1009 | r1 += r0; \ |
1010 | r0 = 0x100000000 ll; \ |
1011 | l1_%=: r0 += 1; \ |
1012 | if r0 < r1 goto l1_%=; \ |
1013 | l0_%=: r0 = 0; \ |
1014 | exit; \ |
1015 | " : |
1016 | : __imm_const(xdp_md_data, offsetof(struct xdp_md, data)), |
1017 | __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end)) |
1018 | : __clobber_all); |
1019 | } |
1020 | |
1021 | SEC("xdp" ) |
1022 | __description("bound check with JMP32_JLT for crossing 32-bit signed boundary" ) |
1023 | __success __retval(0) |
1024 | __naked void crossing_32_bit_signed_boundary_1(void) |
1025 | { |
1026 | asm volatile (" \ |
1027 | r2 = *(u32*)(r1 + %[xdp_md_data]); \ |
1028 | r3 = *(u32*)(r1 + %[xdp_md_data_end]); \ |
1029 | r1 = r2; \ |
1030 | r1 += 1; \ |
1031 | if r1 > r3 goto l0_%=; \ |
1032 | r1 = *(u8*)(r2 + 0); \ |
1033 | w0 = 0x7fffff10; \ |
1034 | w1 += w0; \ |
1035 | w0 = 0x80000000; \ |
1036 | l1_%=: w0 += 1; \ |
1037 | /* r1 unsigned range is [0, 0x8000000f] */ \ |
1038 | if w0 < w1 goto l1_%=; \ |
1039 | l0_%=: r0 = 0; \ |
1040 | exit; \ |
1041 | " : |
1042 | : __imm_const(xdp_md_data, offsetof(struct xdp_md, data)), |
1043 | __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end)) |
1044 | : __clobber_all); |
1045 | } |
1046 | |
1047 | SEC("xdp" ) |
1048 | __description("bound check with JMP32_JSLT for crossing 32-bit signed boundary" ) |
1049 | __success __retval(0) |
1050 | __flag(!BPF_F_TEST_REG_INVARIANTS) /* known invariants violation */ |
1051 | __naked void crossing_32_bit_signed_boundary_2(void) |
1052 | { |
1053 | asm volatile (" \ |
1054 | r2 = *(u32*)(r1 + %[xdp_md_data]); \ |
1055 | r3 = *(u32*)(r1 + %[xdp_md_data_end]); \ |
1056 | r1 = r2; \ |
1057 | r1 += 1; \ |
1058 | if r1 > r3 goto l0_%=; \ |
1059 | r1 = *(u8*)(r2 + 0); \ |
1060 | w0 = 0x7fffff10; \ |
1061 | w1 += w0; \ |
1062 | w2 = 0x80000fff; \ |
1063 | w0 = 0x80000000; \ |
1064 | l1_%=: w0 += 1; \ |
1065 | if w0 s> w2 goto l0_%=; \ |
1066 | /* r1 signed range is [S32_MIN, S32_MAX] */ \ |
1067 | if w0 s< w1 goto l1_%=; \ |
1068 | r0 = 1; \ |
1069 | exit; \ |
1070 | l0_%=: r0 = 0; \ |
1071 | exit; \ |
1072 | " : |
1073 | : __imm_const(xdp_md_data, offsetof(struct xdp_md, data)), |
1074 | __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end)) |
1075 | : __clobber_all); |
1076 | } |
1077 | |
1078 | SEC("tc" ) |
1079 | __description("bounds check with JMP_NE for reg edge" ) |
1080 | __success __retval(0) |
1081 | __naked void reg_not_equal_const(void) |
1082 | { |
1083 | asm volatile (" \ |
1084 | r6 = r1; \ |
1085 | r1 = 0; \ |
1086 | *(u64*)(r10 - 8) = r1; \ |
1087 | call %[bpf_get_prandom_u32]; \ |
1088 | r4 = r0; \ |
1089 | r4 &= 7; \ |
1090 | if r4 != 0 goto l0_%=; \ |
1091 | r0 = 0; \ |
1092 | exit; \ |
1093 | l0_%=: r1 = r6; \ |
1094 | r2 = 0; \ |
1095 | r3 = r10; \ |
1096 | r3 += -8; \ |
1097 | r5 = 0; \ |
1098 | /* The 4th argument of bpf_skb_store_bytes is defined as \ |
1099 | * ARG_CONST_SIZE, so 0 is not allowed. The 'r4 != 0' \ |
1100 | * is providing us this exclusion of zero from initial \ |
1101 | * [0, 7] range. \ |
1102 | */ \ |
1103 | call %[bpf_skb_store_bytes]; \ |
1104 | r0 = 0; \ |
1105 | exit; \ |
1106 | " : |
1107 | : __imm(bpf_get_prandom_u32), |
1108 | __imm(bpf_skb_store_bytes) |
1109 | : __clobber_all); |
1110 | } |
1111 | |
1112 | SEC("tc" ) |
1113 | __description("bounds check with JMP_EQ for reg edge" ) |
1114 | __success __retval(0) |
1115 | __naked void reg_equal_const(void) |
1116 | { |
1117 | asm volatile (" \ |
1118 | r6 = r1; \ |
1119 | r1 = 0; \ |
1120 | *(u64*)(r10 - 8) = r1; \ |
1121 | call %[bpf_get_prandom_u32]; \ |
1122 | r4 = r0; \ |
1123 | r4 &= 7; \ |
1124 | if r4 == 0 goto l0_%=; \ |
1125 | r1 = r6; \ |
1126 | r2 = 0; \ |
1127 | r3 = r10; \ |
1128 | r3 += -8; \ |
1129 | r5 = 0; \ |
1130 | /* Just the same as what we do in reg_not_equal_const() */ \ |
1131 | call %[bpf_skb_store_bytes]; \ |
1132 | l0_%=: r0 = 0; \ |
1133 | exit; \ |
1134 | " : |
1135 | : __imm(bpf_get_prandom_u32), |
1136 | __imm(bpf_skb_store_bytes) |
1137 | : __clobber_all); |
1138 | } |
1139 | |
1140 | char _license[] SEC("license" ) = "GPL" ; |
1141 | |