1 // SPDX-License-Identifier: GPL-2.0
2 /* Converted from tools/testing/selftests/bpf/verifier/bounds_mix_sign_unsign.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("bounds checks mixing signed and unsigned, positive bounds")
17 __failure __msg("unbounded min value")
18 __failure_unpriv
signed_and_unsigned_positive_bounds(void)19 __naked void signed_and_unsigned_positive_bounds(void)
20 {
21 asm volatile (" \
22 call %[bpf_ktime_get_ns]; \
23 *(u64*)(r10 - 16) = r0; \
24 r1 = 0; \
25 *(u64*)(r10 - 8) = r1; \
26 r2 = r10; \
27 r2 += -8; \
28 r1 = %[map_hash_8b] ll; \
29 call %[bpf_map_lookup_elem]; \
30 if r0 == 0 goto l0_%=; \
31 r1 = *(u64*)(r10 - 16); \
32 r2 = 2; \
33 if r2 >= r1 goto l0_%=; \
34 if r1 s> 4 goto l0_%=; \
35 r0 += r1; \
36 r1 = 0; \
37 *(u8*)(r0 + 0) = r1; \
38 l0_%=: r0 = 0; \
39 exit; \
40 " :
41 : __imm(bpf_ktime_get_ns),
42 __imm(bpf_map_lookup_elem),
43 __imm_addr(map_hash_8b)
44 : __clobber_all);
45 }
46
47 SEC("socket")
48 __description("bounds checks mixing signed and unsigned")
49 __failure __msg("unbounded min value")
50 __failure_unpriv
checks_mixing_signed_and_unsigned(void)51 __naked void checks_mixing_signed_and_unsigned(void)
52 {
53 asm volatile (" \
54 call %[bpf_ktime_get_ns]; \
55 *(u64*)(r10 - 16) = r0; \
56 r1 = 0; \
57 *(u64*)(r10 - 8) = r1; \
58 r2 = r10; \
59 r2 += -8; \
60 r1 = %[map_hash_8b] ll; \
61 call %[bpf_map_lookup_elem]; \
62 if r0 == 0 goto l0_%=; \
63 r1 = *(u64*)(r10 - 16); \
64 r2 = -1; \
65 if r1 > r2 goto l0_%=; \
66 if r1 s> 1 goto l0_%=; \
67 r0 += r1; \
68 r1 = 0; \
69 *(u8*)(r0 + 0) = r1; \
70 l0_%=: r0 = 0; \
71 exit; \
72 " :
73 : __imm(bpf_ktime_get_ns),
74 __imm(bpf_map_lookup_elem),
75 __imm_addr(map_hash_8b)
76 : __clobber_all);
77 }
78
79 SEC("socket")
80 __description("bounds checks mixing signed and unsigned, variant 2")
81 __failure __msg("unbounded min value")
82 __failure_unpriv
signed_and_unsigned_variant_2(void)83 __naked void signed_and_unsigned_variant_2(void)
84 {
85 asm volatile (" \
86 call %[bpf_ktime_get_ns]; \
87 *(u64*)(r10 - 16) = r0; \
88 r1 = 0; \
89 *(u64*)(r10 - 8) = r1; \
90 r2 = r10; \
91 r2 += -8; \
92 r1 = %[map_hash_8b] ll; \
93 call %[bpf_map_lookup_elem]; \
94 if r0 == 0 goto l0_%=; \
95 r1 = *(u64*)(r10 - 16); \
96 r2 = -1; \
97 if r1 > r2 goto l0_%=; \
98 r8 = 0; \
99 r8 += r1; \
100 if r8 s> 1 goto l0_%=; \
101 r0 += r8; \
102 r0 = 0; \
103 *(u8*)(r8 + 0) = r0; \
104 l0_%=: r0 = 0; \
105 exit; \
106 " :
107 : __imm(bpf_ktime_get_ns),
108 __imm(bpf_map_lookup_elem),
109 __imm_addr(map_hash_8b)
110 : __clobber_all);
111 }
112
113 SEC("socket")
114 __description("bounds checks mixing signed and unsigned, variant 3")
115 __failure __msg("unbounded min value")
116 __failure_unpriv
signed_and_unsigned_variant_3(void)117 __naked void signed_and_unsigned_variant_3(void)
118 {
119 asm volatile (" \
120 call %[bpf_ktime_get_ns]; \
121 *(u64*)(r10 - 16) = r0; \
122 r1 = 0; \
123 *(u64*)(r10 - 8) = r1; \
124 r2 = r10; \
125 r2 += -8; \
126 r1 = %[map_hash_8b] ll; \
127 call %[bpf_map_lookup_elem]; \
128 if r0 == 0 goto l0_%=; \
129 r1 = *(u64*)(r10 - 16); \
130 r2 = -1; \
131 if r1 > r2 goto l0_%=; \
132 r8 = r1; \
133 if r8 s> 1 goto l0_%=; \
134 r0 += r8; \
135 r0 = 0; \
136 *(u8*)(r8 + 0) = r0; \
137 l0_%=: r0 = 0; \
138 exit; \
139 " :
140 : __imm(bpf_ktime_get_ns),
141 __imm(bpf_map_lookup_elem),
142 __imm_addr(map_hash_8b)
143 : __clobber_all);
144 }
145
146 SEC("socket")
147 __description("bounds checks mixing signed and unsigned, variant 4")
148 __success __success_unpriv __retval(0)
signed_and_unsigned_variant_4(void)149 __naked void signed_and_unsigned_variant_4(void)
150 {
151 asm volatile (" \
152 call %[bpf_ktime_get_ns]; \
153 *(u64*)(r10 - 16) = r0; \
154 r1 = 0; \
155 *(u64*)(r10 - 8) = r1; \
156 r2 = r10; \
157 r2 += -8; \
158 r1 = %[map_hash_8b] ll; \
159 call %[bpf_map_lookup_elem]; \
160 if r0 == 0 goto l0_%=; \
161 r1 = *(u64*)(r10 - 16); \
162 r2 = 1; \
163 r1 &= r2; \
164 if r1 s> 1 goto l0_%=; \
165 r0 += r1; \
166 r1 = 0; \
167 *(u8*)(r0 + 0) = r1; \
168 l0_%=: r0 = 0; \
169 exit; \
170 " :
171 : __imm(bpf_ktime_get_ns),
172 __imm(bpf_map_lookup_elem),
173 __imm_addr(map_hash_8b)
174 : __clobber_all);
175 }
176
177 SEC("socket")
178 __description("bounds checks mixing signed and unsigned, variant 5")
179 __failure __msg("unbounded min value")
180 __failure_unpriv
signed_and_unsigned_variant_5(void)181 __naked void signed_and_unsigned_variant_5(void)
182 {
183 asm volatile (" \
184 call %[bpf_ktime_get_ns]; \
185 *(u64*)(r10 - 16) = r0; \
186 r1 = 0; \
187 *(u64*)(r10 - 8) = r1; \
188 r2 = r10; \
189 r2 += -8; \
190 r1 = %[map_hash_8b] ll; \
191 call %[bpf_map_lookup_elem]; \
192 if r0 == 0 goto l0_%=; \
193 r1 = *(u64*)(r10 - 16); \
194 r2 = -1; \
195 if r1 > r2 goto l0_%=; \
196 if r1 s> 1 goto l0_%=; \
197 r0 += 4; \
198 r0 -= r1; \
199 r1 = 0; \
200 *(u8*)(r0 + 0) = r1; \
201 r0 = 0; \
202 l0_%=: exit; \
203 " :
204 : __imm(bpf_ktime_get_ns),
205 __imm(bpf_map_lookup_elem),
206 __imm_addr(map_hash_8b)
207 : __clobber_all);
208 }
209
210 SEC("socket")
211 __description("bounds checks mixing signed and unsigned, variant 6")
212 __failure __msg("R4 min value is negative, either use unsigned")
213 __failure_unpriv
signed_and_unsigned_variant_6(void)214 __naked void signed_and_unsigned_variant_6(void)
215 {
216 asm volatile (" \
217 r9 = r1; \
218 call %[bpf_ktime_get_ns]; \
219 *(u64*)(r10 - 16) = r0; \
220 r1 = r9; \
221 r2 = 0; \
222 r3 = r10; \
223 r3 += -512; \
224 r4 = *(u64*)(r10 - 16); \
225 r6 = -1; \
226 if r4 > r6 goto l0_%=; \
227 if r4 s> 1 goto l0_%=; \
228 r4 += 1; \
229 r5 = 0; \
230 r6 = 0; \
231 *(u16*)(r10 - 512) = r6; \
232 call %[bpf_skb_load_bytes]; \
233 l0_%=: r0 = 0; \
234 exit; \
235 " :
236 : __imm(bpf_ktime_get_ns),
237 __imm(bpf_skb_load_bytes)
238 : __clobber_all);
239 }
240
241 SEC("socket")
242 __description("bounds checks mixing signed and unsigned, variant 7")
243 __success __success_unpriv __retval(0)
signed_and_unsigned_variant_7(void)244 __naked void signed_and_unsigned_variant_7(void)
245 {
246 asm volatile (" \
247 call %[bpf_ktime_get_ns]; \
248 *(u64*)(r10 - 16) = r0; \
249 r1 = 0; \
250 *(u64*)(r10 - 8) = r1; \
251 r2 = r10; \
252 r2 += -8; \
253 r1 = %[map_hash_8b] ll; \
254 call %[bpf_map_lookup_elem]; \
255 if r0 == 0 goto l0_%=; \
256 r1 = *(u64*)(r10 - 16); \
257 r2 = %[__imm_0]; \
258 if r1 > r2 goto l0_%=; \
259 if r1 s> 1 goto l0_%=; \
260 r0 += r1; \
261 r1 = 0; \
262 *(u8*)(r0 + 0) = r1; \
263 l0_%=: r0 = 0; \
264 exit; \
265 " :
266 : __imm(bpf_ktime_get_ns),
267 __imm(bpf_map_lookup_elem),
268 __imm_addr(map_hash_8b),
269 __imm_const(__imm_0, 1024 * 1024 * 1024)
270 : __clobber_all);
271 }
272
273 SEC("socket")
274 __description("bounds checks mixing signed and unsigned, variant 8")
275 __failure __msg("unbounded min value")
276 __failure_unpriv
signed_and_unsigned_variant_8(void)277 __naked void signed_and_unsigned_variant_8(void)
278 {
279 asm volatile (" \
280 call %[bpf_ktime_get_ns]; \
281 *(u64*)(r10 - 16) = r0; \
282 r1 = 0; \
283 *(u64*)(r10 - 8) = r1; \
284 r2 = r10; \
285 r2 += -8; \
286 r1 = %[map_hash_8b] ll; \
287 call %[bpf_map_lookup_elem]; \
288 if r0 == 0 goto l0_%=; \
289 r1 = *(u64*)(r10 - 16); \
290 r2 = -1; \
291 if r2 > r1 goto l1_%=; \
292 r0 = 0; \
293 exit; \
294 l1_%=: if r1 s> 1 goto l0_%=; \
295 r0 += r1; \
296 r1 = 0; \
297 *(u8*)(r0 + 0) = r1; \
298 l0_%=: r0 = 0; \
299 exit; \
300 " :
301 : __imm(bpf_ktime_get_ns),
302 __imm(bpf_map_lookup_elem),
303 __imm_addr(map_hash_8b)
304 : __clobber_all);
305 }
306
307 SEC("socket")
308 __description("bounds checks mixing signed and unsigned, variant 9")
309 __success __success_unpriv __retval(0)
signed_and_unsigned_variant_9(void)310 __naked void signed_and_unsigned_variant_9(void)
311 {
312 asm volatile (" \
313 call %[bpf_ktime_get_ns]; \
314 *(u64*)(r10 - 16) = r0; \
315 r1 = 0; \
316 *(u64*)(r10 - 8) = r1; \
317 r2 = r10; \
318 r2 += -8; \
319 r1 = %[map_hash_8b] ll; \
320 call %[bpf_map_lookup_elem]; \
321 if r0 == 0 goto l0_%=; \
322 r1 = *(u64*)(r10 - 16); \
323 r2 = -9223372036854775808ULL ll; \
324 if r2 > r1 goto l1_%=; \
325 r0 = 0; \
326 exit; \
327 l1_%=: if r1 s> 1 goto l0_%=; \
328 r0 += r1; \
329 r1 = 0; \
330 *(u8*)(r0 + 0) = r1; \
331 l0_%=: r0 = 0; \
332 exit; \
333 " :
334 : __imm(bpf_ktime_get_ns),
335 __imm(bpf_map_lookup_elem),
336 __imm_addr(map_hash_8b)
337 : __clobber_all);
338 }
339
340 SEC("socket")
341 __description("bounds checks mixing signed and unsigned, variant 10")
342 __failure __msg("unbounded min value")
343 __failure_unpriv
signed_and_unsigned_variant_10(void)344 __naked void signed_and_unsigned_variant_10(void)
345 {
346 asm volatile (" \
347 call %[bpf_ktime_get_ns]; \
348 *(u64*)(r10 - 16) = r0; \
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 = *(u64*)(r10 - 16); \
357 r2 = -1; \
358 if r2 > r1 goto l1_%=; \
359 r0 = 0; \
360 exit; \
361 l1_%=: if r1 s> 1 goto l0_%=; \
362 r0 += r1; \
363 r1 = 0; \
364 *(u8*)(r0 + 0) = r1; \
365 l0_%=: r0 = 0; \
366 exit; \
367 " :
368 : __imm(bpf_ktime_get_ns),
369 __imm(bpf_map_lookup_elem),
370 __imm_addr(map_hash_8b)
371 : __clobber_all);
372 }
373
374 SEC("socket")
375 __description("bounds checks mixing signed and unsigned, variant 11")
376 __failure __msg("unbounded min value")
377 __failure_unpriv
signed_and_unsigned_variant_11(void)378 __naked void signed_and_unsigned_variant_11(void)
379 {
380 asm volatile (" \
381 call %[bpf_ktime_get_ns]; \
382 *(u64*)(r10 - 16) = r0; \
383 r1 = 0; \
384 *(u64*)(r10 - 8) = r1; \
385 r2 = r10; \
386 r2 += -8; \
387 r1 = %[map_hash_8b] ll; \
388 call %[bpf_map_lookup_elem]; \
389 if r0 == 0 goto l0_%=; \
390 r1 = *(u64*)(r10 - 16); \
391 r2 = -1; \
392 if r2 >= r1 goto l1_%=; \
393 /* Dead branch. */ \
394 r0 = 0; \
395 exit; \
396 l1_%=: if r1 s> 1 goto l0_%=; \
397 r0 += r1; \
398 r1 = 0; \
399 *(u8*)(r0 + 0) = r1; \
400 l0_%=: r0 = 0; \
401 exit; \
402 " :
403 : __imm(bpf_ktime_get_ns),
404 __imm(bpf_map_lookup_elem),
405 __imm_addr(map_hash_8b)
406 : __clobber_all);
407 }
408
409 SEC("socket")
410 __description("bounds checks mixing signed and unsigned, variant 12")
411 __failure __msg("unbounded min value")
412 __failure_unpriv
signed_and_unsigned_variant_12(void)413 __naked void signed_and_unsigned_variant_12(void)
414 {
415 asm volatile (" \
416 call %[bpf_ktime_get_ns]; \
417 *(u64*)(r10 - 16) = r0; \
418 r1 = 0; \
419 *(u64*)(r10 - 8) = r1; \
420 r2 = r10; \
421 r2 += -8; \
422 r1 = %[map_hash_8b] ll; \
423 call %[bpf_map_lookup_elem]; \
424 if r0 == 0 goto l0_%=; \
425 r1 = *(u64*)(r10 - 16); \
426 r2 = -6; \
427 if r2 >= r1 goto l1_%=; \
428 r0 = 0; \
429 exit; \
430 l1_%=: if r1 s> 1 goto l0_%=; \
431 r0 += r1; \
432 r1 = 0; \
433 *(u8*)(r0 + 0) = r1; \
434 l0_%=: r0 = 0; \
435 exit; \
436 " :
437 : __imm(bpf_ktime_get_ns),
438 __imm(bpf_map_lookup_elem),
439 __imm_addr(map_hash_8b)
440 : __clobber_all);
441 }
442
443 SEC("socket")
444 __description("bounds checks mixing signed and unsigned, variant 13")
445 __failure __msg("unbounded min value")
446 __failure_unpriv
signed_and_unsigned_variant_13(void)447 __naked void signed_and_unsigned_variant_13(void)
448 {
449 asm volatile (" \
450 call %[bpf_ktime_get_ns]; \
451 *(u64*)(r10 - 16) = r0; \
452 r1 = 0; \
453 *(u64*)(r10 - 8) = r1; \
454 r2 = r10; \
455 r2 += -8; \
456 r1 = %[map_hash_8b] ll; \
457 call %[bpf_map_lookup_elem]; \
458 if r0 == 0 goto l0_%=; \
459 r1 = *(u64*)(r10 - 16); \
460 r2 = 2; \
461 if r2 >= r1 goto l0_%=; \
462 r7 = 1; \
463 if r7 s> 0 goto l1_%=; \
464 l0_%=: r0 = 0; \
465 exit; \
466 l1_%=: r7 += r1; \
467 if r7 s> 4 goto l2_%=; \
468 r0 += r7; \
469 r1 = 0; \
470 *(u8*)(r0 + 0) = r1; \
471 l2_%=: r0 = 0; \
472 exit; \
473 " :
474 : __imm(bpf_ktime_get_ns),
475 __imm(bpf_map_lookup_elem),
476 __imm_addr(map_hash_8b)
477 : __clobber_all);
478 }
479
480 SEC("socket")
481 __description("bounds checks mixing signed and unsigned, variant 14")
482 __failure __msg("unbounded min value")
483 __failure_unpriv
signed_and_unsigned_variant_14(void)484 __naked void signed_and_unsigned_variant_14(void)
485 {
486 asm volatile (" \
487 r9 = *(u32*)(r1 + %[__sk_buff_mark]); \
488 call %[bpf_ktime_get_ns]; \
489 *(u64*)(r10 - 16) = r0; \
490 r1 = 0; \
491 *(u64*)(r10 - 8) = r1; \
492 r2 = r10; \
493 r2 += -8; \
494 r1 = %[map_hash_8b] ll; \
495 call %[bpf_map_lookup_elem]; \
496 if r0 == 0 goto l0_%=; \
497 r1 = *(u64*)(r10 - 16); \
498 r2 = -1; \
499 r8 = 2; \
500 if r9 == 42 goto l1_%=; \
501 if r8 s> r1 goto l2_%=; \
502 l3_%=: if r1 s> 1 goto l2_%=; \
503 r0 += r1; \
504 l0_%=: r1 = 0; \
505 *(u8*)(r0 + 0) = r1; \
506 l2_%=: r0 = 0; \
507 exit; \
508 l1_%=: if r1 > r2 goto l2_%=; \
509 goto l3_%=; \
510 " :
511 : __imm(bpf_ktime_get_ns),
512 __imm(bpf_map_lookup_elem),
513 __imm_addr(map_hash_8b),
514 __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
515 : __clobber_all);
516 }
517
518 SEC("socket")
519 __description("bounds checks mixing signed and unsigned, variant 15")
520 __failure __msg("unbounded min value")
521 __failure_unpriv
signed_and_unsigned_variant_15(void)522 __naked void signed_and_unsigned_variant_15(void)
523 {
524 asm volatile (" \
525 call %[bpf_ktime_get_ns]; \
526 *(u64*)(r10 - 16) = r0; \
527 r1 = 0; \
528 *(u64*)(r10 - 8) = r1; \
529 r2 = r10; \
530 r2 += -8; \
531 r1 = %[map_hash_8b] ll; \
532 call %[bpf_map_lookup_elem]; \
533 if r0 == 0 goto l0_%=; \
534 r1 = *(u64*)(r10 - 16); \
535 r2 = -6; \
536 if r2 >= r1 goto l1_%=; \
537 l0_%=: r0 = 0; \
538 exit; \
539 l1_%=: r0 += r1; \
540 if r0 > 1 goto l2_%=; \
541 r0 = 0; \
542 exit; \
543 l2_%=: r1 = 0; \
544 *(u8*)(r0 + 0) = r1; \
545 r0 = 0; \
546 exit; \
547 " :
548 : __imm(bpf_ktime_get_ns),
549 __imm(bpf_map_lookup_elem),
550 __imm_addr(map_hash_8b)
551 : __clobber_all);
552 }
553
554 char _license[] SEC("license") = "GPL";
555