1 // SPDX-License-Identifier: GPL-2.0
2 /* Converted from tools/testing/selftests/bpf/verifier/array_access.c */
3
4 #include <linux/bpf.h>
5 #include <bpf/bpf_helpers.h>
6 #include "bpf_misc.h"
7
8 #define MAX_ENTRIES 11
9
10 struct test_val {
11 unsigned int index;
12 int foo[MAX_ENTRIES];
13 };
14
15 struct {
16 __uint(type, BPF_MAP_TYPE_ARRAY);
17 __uint(max_entries, 1);
18 __type(key, int);
19 __type(value, struct test_val);
20 __uint(map_flags, BPF_F_RDONLY_PROG);
21 } map_array_ro SEC(".maps");
22
23 struct {
24 __uint(type, BPF_MAP_TYPE_ARRAY);
25 __uint(max_entries, 1);
26 __type(key, int);
27 __type(value, struct test_val);
28 __uint(map_flags, BPF_F_WRONLY_PROG);
29 } map_array_wo SEC(".maps");
30
31 struct {
32 __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
33 __uint(max_entries, 2);
34 __type(key, __u32);
35 __type(value, struct test_val);
36 } map_array_pcpu SEC(".maps");
37
38 struct {
39 __uint(type, BPF_MAP_TYPE_ARRAY);
40 __uint(max_entries, 2);
41 __type(key, __u32);
42 __type(value, struct test_val);
43 } map_array SEC(".maps");
44
45 struct {
46 __uint(type, BPF_MAP_TYPE_HASH);
47 __uint(max_entries, 1);
48 __type(key, long long);
49 __type(value, struct test_val);
50 } map_hash_48b SEC(".maps");
51
52 SEC("socket")
53 __description("valid map access into an array with a constant")
54 __success __failure_unpriv __msg_unpriv("R0 leaks addr")
55 __retval(0)
an_array_with_a_constant_1(void)56 __naked void an_array_with_a_constant_1(void)
57 {
58 asm volatile (" \
59 r1 = 0; \
60 *(u64*)(r10 - 8) = r1; \
61 r2 = r10; \
62 r2 += -8; \
63 r1 = %[map_hash_48b] ll; \
64 call %[bpf_map_lookup_elem]; \
65 if r0 == 0 goto l0_%=; \
66 r1 = %[test_val_foo]; \
67 *(u64*)(r0 + 0) = r1; \
68 l0_%=: exit; \
69 " :
70 : __imm(bpf_map_lookup_elem),
71 __imm_addr(map_hash_48b),
72 __imm_const(test_val_foo, offsetof(struct test_val, foo))
73 : __clobber_all);
74 }
75
76 SEC("socket")
77 __description("valid map access into an array with a register")
78 __success __failure_unpriv __msg_unpriv("R0 leaks addr")
__flag(BPF_F_ANY_ALIGNMENT)79 __retval(0) __flag(BPF_F_ANY_ALIGNMENT)
80 __naked void an_array_with_a_register_1(void)
81 {
82 asm volatile (" \
83 r1 = 0; \
84 *(u64*)(r10 - 8) = r1; \
85 r2 = r10; \
86 r2 += -8; \
87 r1 = %[map_hash_48b] ll; \
88 call %[bpf_map_lookup_elem]; \
89 if r0 == 0 goto l0_%=; \
90 r1 = 4; \
91 r1 <<= 2; \
92 r0 += r1; \
93 r1 = %[test_val_foo]; \
94 *(u64*)(r0 + 0) = r1; \
95 l0_%=: exit; \
96 " :
97 : __imm(bpf_map_lookup_elem),
98 __imm_addr(map_hash_48b),
99 __imm_const(test_val_foo, offsetof(struct test_val, foo))
100 : __clobber_all);
101 }
102
103 SEC("socket")
104 __description("valid map access into an array with a variable")
105 __success __failure_unpriv __msg_unpriv("R0 leaks addr")
__flag(BPF_F_ANY_ALIGNMENT)106 __retval(0) __flag(BPF_F_ANY_ALIGNMENT)
107 __naked void an_array_with_a_variable_1(void)
108 {
109 asm volatile (" \
110 r1 = 0; \
111 *(u64*)(r10 - 8) = r1; \
112 r2 = r10; \
113 r2 += -8; \
114 r1 = %[map_hash_48b] ll; \
115 call %[bpf_map_lookup_elem]; \
116 if r0 == 0 goto l0_%=; \
117 r1 = *(u32*)(r0 + 0); \
118 if r1 >= %[max_entries] goto l0_%=; \
119 r1 <<= 2; \
120 r0 += r1; \
121 r1 = %[test_val_foo]; \
122 *(u64*)(r0 + 0) = r1; \
123 l0_%=: exit; \
124 " :
125 : __imm(bpf_map_lookup_elem),
126 __imm_addr(map_hash_48b),
127 __imm_const(max_entries, MAX_ENTRIES),
128 __imm_const(test_val_foo, offsetof(struct test_val, foo))
129 : __clobber_all);
130 }
131
132 SEC("socket")
133 __description("valid map access into an array with a signed variable")
134 __success __failure_unpriv __msg_unpriv("R0 leaks addr")
__flag(BPF_F_ANY_ALIGNMENT)135 __retval(0) __flag(BPF_F_ANY_ALIGNMENT)
136 __naked void array_with_a_signed_variable(void)
137 {
138 asm volatile (" \
139 r1 = 0; \
140 *(u64*)(r10 - 8) = r1; \
141 r2 = r10; \
142 r2 += -8; \
143 r1 = %[map_hash_48b] ll; \
144 call %[bpf_map_lookup_elem]; \
145 if r0 == 0 goto l0_%=; \
146 r1 = *(u32*)(r0 + 0); \
147 if w1 s> 0xffffffff goto l1_%=; \
148 w1 = 0; \
149 l1_%=: w2 = %[max_entries]; \
150 if r2 s> r1 goto l2_%=; \
151 w1 = 0; \
152 l2_%=: w1 <<= 2; \
153 r0 += r1; \
154 r1 = %[test_val_foo]; \
155 *(u64*)(r0 + 0) = r1; \
156 l0_%=: exit; \
157 " :
158 : __imm(bpf_map_lookup_elem),
159 __imm_addr(map_hash_48b),
160 __imm_const(max_entries, MAX_ENTRIES),
161 __imm_const(test_val_foo, offsetof(struct test_val, foo))
162 : __clobber_all);
163 }
164
165 SEC("socket")
166 __description("invalid map access into an array with a constant")
167 __failure __msg("invalid access to map value, value_size=48 off=48 size=8")
168 __failure_unpriv
an_array_with_a_constant_2(void)169 __naked void an_array_with_a_constant_2(void)
170 {
171 asm volatile (" \
172 r1 = 0; \
173 *(u64*)(r10 - 8) = r1; \
174 r2 = r10; \
175 r2 += -8; \
176 r1 = %[map_hash_48b] ll; \
177 call %[bpf_map_lookup_elem]; \
178 if r0 == 0 goto l0_%=; \
179 r1 = %[test_val_foo]; \
180 *(u64*)(r0 + %[__imm_0]) = r1; \
181 l0_%=: exit; \
182 " :
183 : __imm(bpf_map_lookup_elem),
184 __imm_addr(map_hash_48b),
185 __imm_const(__imm_0, (MAX_ENTRIES + 1) << 2),
186 __imm_const(test_val_foo, offsetof(struct test_val, foo))
187 : __clobber_all);
188 }
189
190 SEC("socket")
191 __description("invalid map access into an array with a register")
192 __failure __msg("R0 min value is outside of the allowed memory range")
193 __failure_unpriv
__flag(BPF_F_ANY_ALIGNMENT)194 __flag(BPF_F_ANY_ALIGNMENT)
195 __naked void an_array_with_a_register_2(void)
196 {
197 asm volatile (" \
198 r1 = 0; \
199 *(u64*)(r10 - 8) = r1; \
200 r2 = r10; \
201 r2 += -8; \
202 r1 = %[map_hash_48b] ll; \
203 call %[bpf_map_lookup_elem]; \
204 if r0 == 0 goto l0_%=; \
205 r1 = %[__imm_0]; \
206 r1 <<= 2; \
207 r0 += r1; \
208 r1 = %[test_val_foo]; \
209 *(u64*)(r0 + 0) = r1; \
210 l0_%=: exit; \
211 " :
212 : __imm(bpf_map_lookup_elem),
213 __imm_addr(map_hash_48b),
214 __imm_const(__imm_0, MAX_ENTRIES + 1),
215 __imm_const(test_val_foo, offsetof(struct test_val, foo))
216 : __clobber_all);
217 }
218
219 SEC("socket")
220 __description("invalid map access into an array with a variable")
221 __failure
222 __msg("R0 unbounded memory access, make sure to bounds check any such access")
223 __failure_unpriv
__flag(BPF_F_ANY_ALIGNMENT)224 __flag(BPF_F_ANY_ALIGNMENT)
225 __naked void an_array_with_a_variable_2(void)
226 {
227 asm volatile (" \
228 r1 = 0; \
229 *(u64*)(r10 - 8) = r1; \
230 r2 = r10; \
231 r2 += -8; \
232 r1 = %[map_hash_48b] ll; \
233 call %[bpf_map_lookup_elem]; \
234 if r0 == 0 goto l0_%=; \
235 r1 = *(u32*)(r0 + 0); \
236 r1 <<= 2; \
237 r0 += r1; \
238 r1 = %[test_val_foo]; \
239 *(u64*)(r0 + 0) = r1; \
240 l0_%=: exit; \
241 " :
242 : __imm(bpf_map_lookup_elem),
243 __imm_addr(map_hash_48b),
244 __imm_const(test_val_foo, offsetof(struct test_val, foo))
245 : __clobber_all);
246 }
247
248 SEC("socket")
249 __description("invalid map access into an array with no floor check")
250 __failure __msg("R0 unbounded memory access")
251 __failure_unpriv __msg_unpriv("R0 leaks addr")
__flag(BPF_F_ANY_ALIGNMENT)252 __flag(BPF_F_ANY_ALIGNMENT)
253 __naked void array_with_no_floor_check(void)
254 {
255 asm volatile (" \
256 r1 = 0; \
257 *(u64*)(r10 - 8) = r1; \
258 r2 = r10; \
259 r2 += -8; \
260 r1 = %[map_hash_48b] ll; \
261 call %[bpf_map_lookup_elem]; \
262 if r0 == 0 goto l0_%=; \
263 r1 = *(u64*)(r0 + 0); \
264 w2 = %[max_entries]; \
265 if r2 s> r1 goto l1_%=; \
266 w1 = 0; \
267 l1_%=: w1 <<= 2; \
268 r0 += r1; \
269 r1 = %[test_val_foo]; \
270 *(u64*)(r0 + 0) = r1; \
271 l0_%=: exit; \
272 " :
273 : __imm(bpf_map_lookup_elem),
274 __imm_addr(map_hash_48b),
275 __imm_const(max_entries, MAX_ENTRIES),
276 __imm_const(test_val_foo, offsetof(struct test_val, foo))
277 : __clobber_all);
278 }
279
280 SEC("socket")
281 __description("invalid map access into an array with a invalid max check")
282 __failure __msg("invalid access to map value, value_size=48 off=44 size=8")
283 __failure_unpriv __msg_unpriv("R0 leaks addr")
__flag(BPF_F_ANY_ALIGNMENT)284 __flag(BPF_F_ANY_ALIGNMENT)
285 __naked void with_a_invalid_max_check_1(void)
286 {
287 asm volatile (" \
288 r1 = 0; \
289 *(u64*)(r10 - 8) = r1; \
290 r2 = r10; \
291 r2 += -8; \
292 r1 = %[map_hash_48b] ll; \
293 call %[bpf_map_lookup_elem]; \
294 if r0 == 0 goto l0_%=; \
295 r1 = *(u32*)(r0 + 0); \
296 w2 = %[__imm_0]; \
297 if r2 > r1 goto l1_%=; \
298 w1 = 0; \
299 l1_%=: w1 <<= 2; \
300 r0 += r1; \
301 r1 = %[test_val_foo]; \
302 *(u64*)(r0 + 0) = r1; \
303 l0_%=: exit; \
304 " :
305 : __imm(bpf_map_lookup_elem),
306 __imm_addr(map_hash_48b),
307 __imm_const(__imm_0, MAX_ENTRIES + 1),
308 __imm_const(test_val_foo, offsetof(struct test_val, foo))
309 : __clobber_all);
310 }
311
312 SEC("socket")
313 __description("invalid map access into an array with a invalid max check")
314 __failure __msg("R0 pointer += pointer")
315 __failure_unpriv
__flag(BPF_F_ANY_ALIGNMENT)316 __flag(BPF_F_ANY_ALIGNMENT)
317 __naked void with_a_invalid_max_check_2(void)
318 {
319 asm volatile (" \
320 r1 = 0; \
321 *(u64*)(r10 - 8) = r1; \
322 r2 = r10; \
323 r2 += -8; \
324 r1 = %[map_hash_48b] ll; \
325 call %[bpf_map_lookup_elem]; \
326 if r0 == 0 goto l0_%=; \
327 r8 = r0; \
328 r1 = 0; \
329 *(u64*)(r10 - 8) = r1; \
330 r2 = r10; \
331 r2 += -8; \
332 r1 = %[map_hash_48b] ll; \
333 call %[bpf_map_lookup_elem]; \
334 if r0 == 0 goto l0_%=; \
335 r0 += r8; \
336 r0 = *(u32*)(r0 + %[test_val_foo]); \
337 l0_%=: exit; \
338 " :
339 : __imm(bpf_map_lookup_elem),
340 __imm_addr(map_hash_48b),
341 __imm_const(test_val_foo, offsetof(struct test_val, foo))
342 : __clobber_all);
343 }
344
345 SEC("socket")
346 __description("valid read map access into a read-only array 1")
347 __success __success_unpriv __retval(28)
a_read_only_array_1_1(void)348 __naked void a_read_only_array_1_1(void)
349 {
350 asm volatile (" \
351 r1 = 0; \
352 *(u64*)(r10 - 8) = r1; \
353 r2 = r10; \
354 r2 += -8; \
355 r1 = %[map_array_ro] ll; \
356 call %[bpf_map_lookup_elem]; \
357 if r0 == 0 goto l0_%=; \
358 r0 = *(u32*)(r0 + 0); \
359 l0_%=: exit; \
360 " :
361 : __imm(bpf_map_lookup_elem),
362 __imm_addr(map_array_ro)
363 : __clobber_all);
364 }
365
366 SEC("tc")
367 __description("valid read map access into a read-only array 2")
368 __success __retval(65507)
a_read_only_array_2_1(void)369 __naked void a_read_only_array_2_1(void)
370 {
371 asm volatile (" \
372 r1 = 0; \
373 *(u64*)(r10 - 8) = r1; \
374 r2 = r10; \
375 r2 += -8; \
376 r1 = %[map_array_ro] ll; \
377 call %[bpf_map_lookup_elem]; \
378 if r0 == 0 goto l0_%=; \
379 r1 = r0; \
380 r2 = 4; \
381 r3 = 0; \
382 r4 = 0; \
383 r5 = 0; \
384 call %[bpf_csum_diff]; \
385 l0_%=: exit; \
386 " :
387 : __imm(bpf_csum_diff),
388 __imm(bpf_map_lookup_elem),
389 __imm_addr(map_array_ro)
390 : __clobber_all);
391 }
392
393 SEC("socket")
394 __description("invalid write map access into a read-only array 1")
395 __failure __msg("write into map forbidden")
396 __failure_unpriv
a_read_only_array_1_2(void)397 __naked void a_read_only_array_1_2(void)
398 {
399 asm volatile (" \
400 r1 = 0; \
401 *(u64*)(r10 - 8) = r1; \
402 r2 = r10; \
403 r2 += -8; \
404 r1 = %[map_array_ro] ll; \
405 call %[bpf_map_lookup_elem]; \
406 if r0 == 0 goto l0_%=; \
407 r1 = 42; \
408 *(u64*)(r0 + 0) = r1; \
409 l0_%=: exit; \
410 " :
411 : __imm(bpf_map_lookup_elem),
412 __imm_addr(map_array_ro)
413 : __clobber_all);
414 }
415
416 SEC("tc")
417 __description("invalid write map access into a read-only array 2")
418 __failure __msg("write into map forbidden")
a_read_only_array_2_2(void)419 __naked void a_read_only_array_2_2(void)
420 {
421 asm volatile (" \
422 r6 = r1; \
423 r1 = 0; \
424 *(u64*)(r10 - 8) = r1; \
425 r2 = r10; \
426 r2 += -8; \
427 r1 = %[map_array_ro] ll; \
428 call %[bpf_map_lookup_elem]; \
429 if r0 == 0 goto l0_%=; \
430 r1 = r6; \
431 r2 = 0; \
432 r3 = r0; \
433 r4 = 8; \
434 call %[bpf_skb_load_bytes]; \
435 l0_%=: exit; \
436 " :
437 : __imm(bpf_map_lookup_elem),
438 __imm(bpf_skb_load_bytes),
439 __imm_addr(map_array_ro)
440 : __clobber_all);
441 }
442
443 SEC("socket")
444 __description("valid write map access into a write-only array 1")
445 __success __success_unpriv __retval(1)
a_write_only_array_1_1(void)446 __naked void a_write_only_array_1_1(void)
447 {
448 asm volatile (" \
449 r1 = 0; \
450 *(u64*)(r10 - 8) = r1; \
451 r2 = r10; \
452 r2 += -8; \
453 r1 = %[map_array_wo] ll; \
454 call %[bpf_map_lookup_elem]; \
455 if r0 == 0 goto l0_%=; \
456 r1 = 42; \
457 *(u64*)(r0 + 0) = r1; \
458 l0_%=: r0 = 1; \
459 exit; \
460 " :
461 : __imm(bpf_map_lookup_elem),
462 __imm_addr(map_array_wo)
463 : __clobber_all);
464 }
465
466 SEC("tc")
467 __description("valid write map access into a write-only array 2")
468 __success __retval(0)
a_write_only_array_2_1(void)469 __naked void a_write_only_array_2_1(void)
470 {
471 asm volatile (" \
472 r6 = r1; \
473 r1 = 0; \
474 *(u64*)(r10 - 8) = r1; \
475 r2 = r10; \
476 r2 += -8; \
477 r1 = %[map_array_wo] ll; \
478 call %[bpf_map_lookup_elem]; \
479 if r0 == 0 goto l0_%=; \
480 r1 = r6; \
481 r2 = 0; \
482 r3 = r0; \
483 r4 = 8; \
484 call %[bpf_skb_load_bytes]; \
485 l0_%=: exit; \
486 " :
487 : __imm(bpf_map_lookup_elem),
488 __imm(bpf_skb_load_bytes),
489 __imm_addr(map_array_wo)
490 : __clobber_all);
491 }
492
493 SEC("socket")
494 __description("invalid read map access into a write-only array 1")
495 __failure __msg("read from map forbidden")
496 __failure_unpriv
a_write_only_array_1_2(void)497 __naked void a_write_only_array_1_2(void)
498 {
499 asm volatile (" \
500 r1 = 0; \
501 *(u64*)(r10 - 8) = r1; \
502 r2 = r10; \
503 r2 += -8; \
504 r1 = %[map_array_wo] ll; \
505 call %[bpf_map_lookup_elem]; \
506 if r0 == 0 goto l0_%=; \
507 r0 = *(u64*)(r0 + 0); \
508 l0_%=: exit; \
509 " :
510 : __imm(bpf_map_lookup_elem),
511 __imm_addr(map_array_wo)
512 : __clobber_all);
513 }
514
515 SEC("tc")
516 __description("invalid read map access into a write-only array 2")
517 __failure __msg("read from map forbidden")
a_write_only_array_2_2(void)518 __naked void a_write_only_array_2_2(void)
519 {
520 asm volatile (" \
521 r1 = 0; \
522 *(u64*)(r10 - 8) = r1; \
523 r2 = r10; \
524 r2 += -8; \
525 r1 = %[map_array_wo] ll; \
526 call %[bpf_map_lookup_elem]; \
527 if r0 == 0 goto l0_%=; \
528 r1 = r0; \
529 r2 = 4; \
530 r3 = 0; \
531 r4 = 0; \
532 r5 = 0; \
533 call %[bpf_csum_diff]; \
534 l0_%=: exit; \
535 " :
536 : __imm(bpf_csum_diff),
537 __imm(bpf_map_lookup_elem),
538 __imm_addr(map_array_wo)
539 : __clobber_all);
540 }
541
542 SEC("socket")
543 __description("valid map access into an array using constant without nullness")
544 __success __retval(4) __log_level(2)
545 __msg("mark_precise: frame0: regs= stack=-8 before {{[0-9]}}: ({{[a-f0-9]+}}) *(u32 *)(r10 -8) = {{(1|r[0-9])}}")
an_array_with_a_constant_no_nullness(void)546 unsigned int an_array_with_a_constant_no_nullness(void)
547 {
548 /* Need 8-byte alignment for spill tracking */
549 __u32 __attribute__((aligned(8))) key = 1;
550 struct test_val *val;
551
552 val = bpf_map_lookup_elem(&map_array, &key);
553 val->index = offsetof(struct test_val, foo);
554
555 return val->index;
556 }
557
558 SEC("socket")
559 __description("valid multiple map access into an array using constant without nullness")
560 __success __retval(8) __log_level(2)
561 __msg("mark_precise: frame0: regs= stack=-8 before {{[0-9]}}: ({{[a-f0-9]+}}) *(u32 *)(r10 -16) = {{(0|r[0-9])}}")
562 __msg("mark_precise: frame0: regs= stack=-8 before {{[0-9]}}: ({{[a-f0-9]+}}) *(u32 *)(r10 -8) = {{(1|r[0-9])}}")
multiple_array_with_a_constant_no_nullness(void)563 unsigned int multiple_array_with_a_constant_no_nullness(void)
564 {
565 __u32 __attribute__((aligned(8))) key = 1;
566 __u32 __attribute__((aligned(8))) key2 = 0;
567 struct test_val *val, *val2;
568
569 val = bpf_map_lookup_elem(&map_array, &key);
570 val->index = offsetof(struct test_val, foo);
571
572 val2 = bpf_map_lookup_elem(&map_array, &key2);
573 val2->index = offsetof(struct test_val, foo);
574
575 return val->index + val2->index;
576 }
577
578 SEC("socket")
579 __description("valid map access into an array using natural aligned 32-bit constant 0 without nullness")
580 __success __retval(4)
an_array_with_a_32bit_constant_0_no_nullness(void)581 unsigned int an_array_with_a_32bit_constant_0_no_nullness(void)
582 {
583 /* Unlike the above tests, 32-bit zeroing is precisely tracked even
584 * if writes are not aligned to BPF_REG_SIZE. This tests that our
585 * STACK_ZERO handling functions.
586 */
587 struct test_val *val;
588 __u32 key = 0;
589
590 val = bpf_map_lookup_elem(&map_array, &key);
591 val->index = offsetof(struct test_val, foo);
592
593 return val->index;
594 }
595
596 SEC("socket")
597 __description("valid map access into a pcpu array using constant without nullness")
598 __success __retval(4) __log_level(2)
599 __msg("mark_precise: frame0: regs= stack=-8 before {{[0-9]}}: ({{[a-f0-9]+}}) *(u32 *)(r10 -8) = {{(1|r[0-9])}}")
a_pcpu_array_with_a_constant_no_nullness(void)600 unsigned int a_pcpu_array_with_a_constant_no_nullness(void)
601 {
602 __u32 __attribute__((aligned(8))) key = 1;
603 struct test_val *val;
604
605 val = bpf_map_lookup_elem(&map_array_pcpu, &key);
606 val->index = offsetof(struct test_val, foo);
607
608 return val->index;
609 }
610
611 SEC("socket")
612 __description("invalid map access into an array using constant without nullness")
613 __failure __msg("R0 invalid mem access 'map_value_or_null'")
an_array_with_a_constant_no_nullness_out_of_bounds(void)614 unsigned int an_array_with_a_constant_no_nullness_out_of_bounds(void)
615 {
616 /* Out of bounds */
617 __u32 __attribute__((aligned(8))) key = 3;
618 struct test_val *val;
619
620 val = bpf_map_lookup_elem(&map_array, &key);
621 val->index = offsetof(struct test_val, foo);
622
623 return val->index;
624 }
625
626 SEC("socket")
627 __description("invalid map access into an array using constant smaller than key_size")
628 __failure __msg("R0 invalid mem access 'map_value_or_null'")
an_array_with_a_constant_too_small(void)629 unsigned int an_array_with_a_constant_too_small(void)
630 {
631 __u32 __attribute__((aligned(8))) key;
632 struct test_val *val;
633
634 /* Mark entire key as STACK_MISC */
635 bpf_probe_read_user(&key, sizeof(key), NULL);
636
637 /* Spilling only the bottom byte results in a tnum const of 1.
638 * We want to check that the verifier rejects it, as the spill is < 4B.
639 */
640 *(__u8 *)&key = 1;
641 val = bpf_map_lookup_elem(&map_array, &key);
642
643 /* Should fail, as verifier cannot prove in-bound lookup */
644 val->index = offsetof(struct test_val, foo);
645
646 return val->index;
647 }
648
649 SEC("socket")
650 __description("invalid map access into an array using constant larger than key_size")
651 __failure __msg("R0 invalid mem access 'map_value_or_null'")
an_array_with_a_constant_too_big(void)652 unsigned int an_array_with_a_constant_too_big(void)
653 {
654 struct test_val *val;
655 __u64 key = 1;
656
657 /* Even if the constant value is < max_entries, if the spill size is
658 * larger than the key size, the set bits may not be where we expect them
659 * to be on different endian architectures.
660 */
661 val = bpf_map_lookup_elem(&map_array, &key);
662 val->index = offsetof(struct test_val, foo);
663
664 return val->index;
665 }
666
667 SEC("socket")
668 __description("invalid elided lookup using const and non-const key")
669 __failure __msg("R0 invalid mem access 'map_value_or_null'")
mixed_const_and_non_const_key_lookup(void)670 unsigned int mixed_const_and_non_const_key_lookup(void)
671 {
672 __u32 __attribute__((aligned(8))) key;
673 struct test_val *val;
674 __u32 rand;
675
676 rand = bpf_get_prandom_u32();
677 key = rand > 42 ? 1 : rand;
678 val = bpf_map_lookup_elem(&map_array, &key);
679
680 return val->index;
681 }
682
683 SEC("socket")
684 __failure __msg("invalid read from stack R2 off=4096 size=4")
key_lookup_at_invalid_fp(void)685 __naked void key_lookup_at_invalid_fp(void)
686 {
687 asm volatile (" \
688 r1 = %[map_array] ll; \
689 r2 = r10; \
690 r2 += 4096; \
691 call %[bpf_map_lookup_elem]; \
692 r0 = *(u64*)(r0 + 0); \
693 exit; \
694 " :
695 : __imm(bpf_map_lookup_elem),
696 __imm_addr(map_array)
697 : __clobber_all);
698 }
699
700 volatile __u32 __attribute__((aligned(8))) global_key;
701
702 SEC("socket")
703 __description("invalid elided lookup using non-stack key")
704 __failure __msg("R0 invalid mem access 'map_value_or_null'")
non_stack_key_lookup(void)705 unsigned int non_stack_key_lookup(void)
706 {
707 struct test_val *val;
708
709 global_key = 1;
710 val = bpf_map_lookup_elem(&map_array, (void *)&global_key);
711 val->index = offsetof(struct test_val, foo);
712
713 return val->index;
714 }
715
716 SEC("socket")
717 __description("doesn't reject UINT64_MAX as s64 for irrelevant maps")
718 __success __retval(42)
doesnt_reject_irrelevant_maps(void)719 unsigned int doesnt_reject_irrelevant_maps(void)
720 {
721 __u64 key = 0xFFFFFFFFFFFFFFFF;
722 struct test_val *val;
723
724 val = bpf_map_lookup_elem(&map_hash_48b, &key);
725 if (val)
726 return val->index;
727
728 return 42;
729 }
730
731 char _license[] SEC("license") = "GPL";
732