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