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