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 |
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 |
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 |
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 |
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) |
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 |
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 |
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) |
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 |
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) |
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 |
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 |
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 |
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 |
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 |
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 |
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 | |