1// SPDX-License-Identifier: GPL-2.0
2/* Converted from tools/testing/selftests/bpf/verifier/helper_access_var_len.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
10struct test_val {
11	unsigned int index;
12	int foo[MAX_ENTRIES];
13};
14
15struct {
16	__uint(type, BPF_MAP_TYPE_HASH);
17	__uint(max_entries, 1);
18	__type(key, long long);
19	__type(value, struct test_val);
20} map_hash_48b SEC(".maps");
21
22struct {
23	__uint(type, BPF_MAP_TYPE_HASH);
24	__uint(max_entries, 1);
25	__type(key, long long);
26	__type(value, long long);
27} map_hash_8b SEC(".maps");
28
29struct {
30	__uint(type, BPF_MAP_TYPE_RINGBUF);
31	__uint(max_entries, 4096);
32} map_ringbuf SEC(".maps");
33
34SEC("tracepoint")
35__description("helper access to variable memory: stack, bitwise AND + JMP, correct bounds")
36__success
37__naked void bitwise_and_jmp_correct_bounds(void)
38{
39	asm volatile ("					\
40	r1 = r10;					\
41	r1 += -64;					\
42	r0 = 0;						\
43	*(u64*)(r10 - 64) = r0;				\
44	*(u64*)(r10 - 56) = r0;				\
45	*(u64*)(r10 - 48) = r0;				\
46	*(u64*)(r10 - 40) = r0;				\
47	*(u64*)(r10 - 32) = r0;				\
48	*(u64*)(r10 - 24) = r0;				\
49	*(u64*)(r10 - 16) = r0;				\
50	*(u64*)(r10 - 8) = r0;				\
51	r2 = 16;					\
52	*(u64*)(r1 - 128) = r2;				\
53	r2 = *(u64*)(r1 - 128);				\
54	r2 &= 64;					\
55	r4 = 0;						\
56	if r4 >= r2 goto l0_%=;				\
57	r3 = 0;						\
58	call %[bpf_probe_read_kernel];			\
59l0_%=:	r0 = 0;						\
60	exit;						\
61"	:
62	: __imm(bpf_probe_read_kernel)
63	: __clobber_all);
64}
65
66SEC("socket")
67__description("helper access to variable memory: stack, bitwise AND, zero included")
68/* in privileged mode reads from uninitialized stack locations are permitted */
69__success __failure_unpriv
70__msg_unpriv("invalid indirect read from stack R2 off -64+0 size 64")
71__retval(0)
72__naked void stack_bitwise_and_zero_included(void)
73{
74	asm volatile ("					\
75	/* set max stack size */			\
76	r6 = 0;						\
77	*(u64*)(r10 - 128) = r6;			\
78	/* set r3 to a random value */			\
79	call %[bpf_get_prandom_u32];			\
80	r3 = r0;					\
81	/* use bitwise AND to limit r3 range to [0, 64] */\
82	r3 &= 64;					\
83	r1 = %[map_ringbuf] ll;				\
84	r2 = r10;					\
85	r2 += -64;					\
86	r4 = 0;						\
87	/* Call bpf_ringbuf_output(), it is one of a few helper functions with\
88	 * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode.\
89	 * For unpriv this should signal an error, because memory at &fp[-64] is\
90	 * not initialized.				\
91	 */						\
92	call %[bpf_ringbuf_output];			\
93	exit;						\
94"	:
95	: __imm(bpf_get_prandom_u32),
96	  __imm(bpf_ringbuf_output),
97	  __imm_addr(map_ringbuf)
98	: __clobber_all);
99}
100
101SEC("tracepoint")
102__description("helper access to variable memory: stack, bitwise AND + JMP, wrong max")
103__failure __msg("invalid indirect access to stack R1 off=-64 size=65")
104__naked void bitwise_and_jmp_wrong_max(void)
105{
106	asm volatile ("					\
107	r2 = *(u64*)(r1 + 8);				\
108	r1 = r10;					\
109	r1 += -64;					\
110	*(u64*)(r1 - 128) = r2;				\
111	r2 = *(u64*)(r1 - 128);				\
112	r2 &= 65;					\
113	r4 = 0;						\
114	if r4 >= r2 goto l0_%=;				\
115	r3 = 0;						\
116	call %[bpf_probe_read_kernel];			\
117l0_%=:	r0 = 0;						\
118	exit;						\
119"	:
120	: __imm(bpf_probe_read_kernel)
121	: __clobber_all);
122}
123
124SEC("tracepoint")
125__description("helper access to variable memory: stack, JMP, correct bounds")
126__success
127__naked void memory_stack_jmp_correct_bounds(void)
128{
129	asm volatile ("					\
130	r1 = r10;					\
131	r1 += -64;					\
132	r0 = 0;						\
133	*(u64*)(r10 - 64) = r0;				\
134	*(u64*)(r10 - 56) = r0;				\
135	*(u64*)(r10 - 48) = r0;				\
136	*(u64*)(r10 - 40) = r0;				\
137	*(u64*)(r10 - 32) = r0;				\
138	*(u64*)(r10 - 24) = r0;				\
139	*(u64*)(r10 - 16) = r0;				\
140	*(u64*)(r10 - 8) = r0;				\
141	r2 = 16;					\
142	*(u64*)(r1 - 128) = r2;				\
143	r2 = *(u64*)(r1 - 128);				\
144	if r2 > 64 goto l0_%=;				\
145	r4 = 0;						\
146	if r4 >= r2 goto l0_%=;				\
147	r3 = 0;						\
148	call %[bpf_probe_read_kernel];			\
149l0_%=:	r0 = 0;						\
150	exit;						\
151"	:
152	: __imm(bpf_probe_read_kernel)
153	: __clobber_all);
154}
155
156SEC("tracepoint")
157__description("helper access to variable memory: stack, JMP (signed), correct bounds")
158__success
159__naked void stack_jmp_signed_correct_bounds(void)
160{
161	asm volatile ("					\
162	r1 = r10;					\
163	r1 += -64;					\
164	r0 = 0;						\
165	*(u64*)(r10 - 64) = r0;				\
166	*(u64*)(r10 - 56) = r0;				\
167	*(u64*)(r10 - 48) = r0;				\
168	*(u64*)(r10 - 40) = r0;				\
169	*(u64*)(r10 - 32) = r0;				\
170	*(u64*)(r10 - 24) = r0;				\
171	*(u64*)(r10 - 16) = r0;				\
172	*(u64*)(r10 - 8) = r0;				\
173	r2 = 16;					\
174	*(u64*)(r1 - 128) = r2;				\
175	r2 = *(u64*)(r1 - 128);				\
176	if r2 s> 64 goto l0_%=;				\
177	r4 = 0;						\
178	if r4 s>= r2 goto l0_%=;			\
179	r3 = 0;						\
180	call %[bpf_probe_read_kernel];			\
181l0_%=:	r0 = 0;						\
182	exit;						\
183"	:
184	: __imm(bpf_probe_read_kernel)
185	: __clobber_all);
186}
187
188SEC("tracepoint")
189__description("helper access to variable memory: stack, JMP, bounds + offset")
190__failure __msg("invalid indirect access to stack R1 off=-64 size=65")
191__naked void memory_stack_jmp_bounds_offset(void)
192{
193	asm volatile ("					\
194	r2 = *(u64*)(r1 + 8);				\
195	r1 = r10;					\
196	r1 += -64;					\
197	*(u64*)(r1 - 128) = r2;				\
198	r2 = *(u64*)(r1 - 128);				\
199	if r2 > 64 goto l0_%=;				\
200	r4 = 0;						\
201	if r4 >= r2 goto l0_%=;				\
202	r2 += 1;					\
203	r3 = 0;						\
204	call %[bpf_probe_read_kernel];			\
205l0_%=:	r0 = 0;						\
206	exit;						\
207"	:
208	: __imm(bpf_probe_read_kernel)
209	: __clobber_all);
210}
211
212SEC("tracepoint")
213__description("helper access to variable memory: stack, JMP, wrong max")
214__failure __msg("invalid indirect access to stack R1 off=-64 size=65")
215__naked void memory_stack_jmp_wrong_max(void)
216{
217	asm volatile ("					\
218	r2 = *(u64*)(r1 + 8);				\
219	r1 = r10;					\
220	r1 += -64;					\
221	*(u64*)(r1 - 128) = r2;				\
222	r2 = *(u64*)(r1 - 128);				\
223	if r2 > 65 goto l0_%=;				\
224	r4 = 0;						\
225	if r4 >= r2 goto l0_%=;				\
226	r3 = 0;						\
227	call %[bpf_probe_read_kernel];			\
228l0_%=:	r0 = 0;						\
229	exit;						\
230"	:
231	: __imm(bpf_probe_read_kernel)
232	: __clobber_all);
233}
234
235SEC("tracepoint")
236__description("helper access to variable memory: stack, JMP, no max check")
237__failure
238/* because max wasn't checked, signed min is negative */
239__msg("R2 min value is negative, either use unsigned or 'var &= const'")
240__naked void stack_jmp_no_max_check(void)
241{
242	asm volatile ("					\
243	r2 = *(u64*)(r1 + 8);				\
244	r1 = r10;					\
245	r1 += -64;					\
246	*(u64*)(r1 - 128) = r2;				\
247	r2 = *(u64*)(r1 - 128);				\
248	r4 = 0;						\
249	if r4 >= r2 goto l0_%=;				\
250	r3 = 0;						\
251	call %[bpf_probe_read_kernel];			\
252l0_%=:	r0 = 0;						\
253	exit;						\
254"	:
255	: __imm(bpf_probe_read_kernel)
256	: __clobber_all);
257}
258
259SEC("socket")
260__description("helper access to variable memory: stack, JMP, no min check")
261/* in privileged mode reads from uninitialized stack locations are permitted */
262__success __failure_unpriv
263__msg_unpriv("invalid indirect read from stack R2 off -64+0 size 64")
264__retval(0)
265__naked void stack_jmp_no_min_check(void)
266{
267	asm volatile ("					\
268	/* set max stack size */			\
269	r6 = 0;						\
270	*(u64*)(r10 - 128) = r6;			\
271	/* set r3 to a random value */			\
272	call %[bpf_get_prandom_u32];			\
273	r3 = r0;					\
274	/* use JMP to limit r3 range to [0, 64] */	\
275	if r3 > 64 goto l0_%=;				\
276	r1 = %[map_ringbuf] ll;				\
277	r2 = r10;					\
278	r2 += -64;					\
279	r4 = 0;						\
280	/* Call bpf_ringbuf_output(), it is one of a few helper functions with\
281	 * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode.\
282	 * For unpriv this should signal an error, because memory at &fp[-64] is\
283	 * not initialized.				\
284	 */						\
285	call %[bpf_ringbuf_output];			\
286l0_%=:	r0 = 0;						\
287	exit;						\
288"	:
289	: __imm(bpf_get_prandom_u32),
290	  __imm(bpf_ringbuf_output),
291	  __imm_addr(map_ringbuf)
292	: __clobber_all);
293}
294
295SEC("tracepoint")
296__description("helper access to variable memory: stack, JMP (signed), no min check")
297__failure __msg("R2 min value is negative")
298__naked void jmp_signed_no_min_check(void)
299{
300	asm volatile ("					\
301	r2 = *(u64*)(r1 + 8);				\
302	r1 = r10;					\
303	r1 += -64;					\
304	*(u64*)(r1 - 128) = r2;				\
305	r2 = *(u64*)(r1 - 128);				\
306	if r2 s> 64 goto l0_%=;				\
307	r3 = 0;						\
308	call %[bpf_probe_read_kernel];			\
309	r0 = 0;						\
310l0_%=:	exit;						\
311"	:
312	: __imm(bpf_probe_read_kernel)
313	: __clobber_all);
314}
315
316SEC("tracepoint")
317__description("helper access to variable memory: map, JMP, correct bounds")
318__success
319__naked void memory_map_jmp_correct_bounds(void)
320{
321	asm volatile ("					\
322	r2 = r10;					\
323	r2 += -8;					\
324	r1 = 0;						\
325	*(u64*)(r2 + 0) = r1;				\
326	r1 = %[map_hash_48b] ll;			\
327	call %[bpf_map_lookup_elem];			\
328	if r0 == 0 goto l0_%=;				\
329	r1 = r0;					\
330	r2 = %[sizeof_test_val];			\
331	*(u64*)(r10 - 128) = r2;			\
332	r2 = *(u64*)(r10 - 128);			\
333	if r2 s> %[sizeof_test_val] goto l1_%=;		\
334	r4 = 0;						\
335	if r4 s>= r2 goto l1_%=;			\
336	r3 = 0;						\
337	call %[bpf_probe_read_kernel];			\
338l1_%=:	r0 = 0;						\
339l0_%=:	exit;						\
340"	:
341	: __imm(bpf_map_lookup_elem),
342	  __imm(bpf_probe_read_kernel),
343	  __imm_addr(map_hash_48b),
344	  __imm_const(sizeof_test_val, sizeof(struct test_val))
345	: __clobber_all);
346}
347
348SEC("tracepoint")
349__description("helper access to variable memory: map, JMP, wrong max")
350__failure __msg("invalid access to map value, value_size=48 off=0 size=49")
351__naked void memory_map_jmp_wrong_max(void)
352{
353	asm volatile ("					\
354	r6 = *(u64*)(r1 + 8);				\
355	r2 = r10;					\
356	r2 += -8;					\
357	r1 = 0;						\
358	*(u64*)(r2 + 0) = r1;				\
359	r1 = %[map_hash_48b] ll;			\
360	call %[bpf_map_lookup_elem];			\
361	if r0 == 0 goto l0_%=;				\
362	r1 = r0;					\
363	r2 = r6;					\
364	*(u64*)(r10 - 128) = r2;			\
365	r2 = *(u64*)(r10 - 128);			\
366	if r2 s> %[__imm_0] goto l1_%=;			\
367	r4 = 0;						\
368	if r4 s>= r2 goto l1_%=;			\
369	r3 = 0;						\
370	call %[bpf_probe_read_kernel];			\
371l1_%=:	r0 = 0;						\
372l0_%=:	exit;						\
373"	:
374	: __imm(bpf_map_lookup_elem),
375	  __imm(bpf_probe_read_kernel),
376	  __imm_addr(map_hash_48b),
377	  __imm_const(__imm_0, sizeof(struct test_val) + 1)
378	: __clobber_all);
379}
380
381SEC("tracepoint")
382__description("helper access to variable memory: map adjusted, JMP, correct bounds")
383__success
384__naked void map_adjusted_jmp_correct_bounds(void)
385{
386	asm volatile ("					\
387	r2 = r10;					\
388	r2 += -8;					\
389	r1 = 0;						\
390	*(u64*)(r2 + 0) = r1;				\
391	r1 = %[map_hash_48b] ll;			\
392	call %[bpf_map_lookup_elem];			\
393	if r0 == 0 goto l0_%=;				\
394	r1 = r0;					\
395	r1 += 20;					\
396	r2 = %[sizeof_test_val];			\
397	*(u64*)(r10 - 128) = r2;			\
398	r2 = *(u64*)(r10 - 128);			\
399	if r2 s> %[__imm_0] goto l1_%=;			\
400	r4 = 0;						\
401	if r4 s>= r2 goto l1_%=;			\
402	r3 = 0;						\
403	call %[bpf_probe_read_kernel];			\
404l1_%=:	r0 = 0;						\
405l0_%=:	exit;						\
406"	:
407	: __imm(bpf_map_lookup_elem),
408	  __imm(bpf_probe_read_kernel),
409	  __imm_addr(map_hash_48b),
410	  __imm_const(__imm_0, sizeof(struct test_val) - 20),
411	  __imm_const(sizeof_test_val, sizeof(struct test_val))
412	: __clobber_all);
413}
414
415SEC("tracepoint")
416__description("helper access to variable memory: map adjusted, JMP, wrong max")
417__failure __msg("R1 min value is outside of the allowed memory range")
418__naked void map_adjusted_jmp_wrong_max(void)
419{
420	asm volatile ("					\
421	r6 = *(u64*)(r1 + 8);				\
422	r2 = r10;					\
423	r2 += -8;					\
424	r1 = 0;						\
425	*(u64*)(r2 + 0) = r1;				\
426	r1 = %[map_hash_48b] ll;			\
427	call %[bpf_map_lookup_elem];			\
428	if r0 == 0 goto l0_%=;				\
429	r1 = r0;					\
430	r1 += 20;					\
431	r2 = r6;					\
432	*(u64*)(r10 - 128) = r2;			\
433	r2 = *(u64*)(r10 - 128);			\
434	if r2 s> %[__imm_0] goto l1_%=;			\
435	r4 = 0;						\
436	if r4 s>= r2 goto l1_%=;			\
437	r3 = 0;						\
438	call %[bpf_probe_read_kernel];			\
439l1_%=:	r0 = 0;						\
440l0_%=:	exit;						\
441"	:
442	: __imm(bpf_map_lookup_elem),
443	  __imm(bpf_probe_read_kernel),
444	  __imm_addr(map_hash_48b),
445	  __imm_const(__imm_0, sizeof(struct test_val) - 19)
446	: __clobber_all);
447}
448
449SEC("tc")
450__description("helper access to variable memory: size = 0 allowed on NULL (ARG_PTR_TO_MEM_OR_NULL)")
451__success __retval(0)
452__naked void ptr_to_mem_or_null_1(void)
453{
454	asm volatile ("					\
455	r1 = 0;						\
456	r2 = 0;						\
457	r3 = 0;						\
458	r4 = 0;						\
459	r5 = 0;						\
460	call %[bpf_csum_diff];				\
461	exit;						\
462"	:
463	: __imm(bpf_csum_diff)
464	: __clobber_all);
465}
466
467SEC("tc")
468__description("helper access to variable memory: size > 0 not allowed on NULL (ARG_PTR_TO_MEM_OR_NULL)")
469__failure __msg("R1 type=scalar expected=fp")
470__naked void ptr_to_mem_or_null_2(void)
471{
472	asm volatile ("					\
473	r2 = *(u32*)(r1 + 0);				\
474	r1 = 0;						\
475	*(u64*)(r10 - 128) = r2;			\
476	r2 = *(u64*)(r10 - 128);			\
477	r2 &= 64;					\
478	r3 = 0;						\
479	r4 = 0;						\
480	r5 = 0;						\
481	call %[bpf_csum_diff];				\
482	exit;						\
483"	:
484	: __imm(bpf_csum_diff)
485	: __clobber_all);
486}
487
488SEC("tc")
489__description("helper access to variable memory: size = 0 allowed on != NULL stack pointer (ARG_PTR_TO_MEM_OR_NULL)")
490__success __retval(0)
491__naked void ptr_to_mem_or_null_3(void)
492{
493	asm volatile ("					\
494	r1 = r10;					\
495	r1 += -8;					\
496	r2 = 0;						\
497	*(u64*)(r1 + 0) = r2;				\
498	r2 &= 8;					\
499	r3 = 0;						\
500	r4 = 0;						\
501	r5 = 0;						\
502	call %[bpf_csum_diff];				\
503	exit;						\
504"	:
505	: __imm(bpf_csum_diff)
506	: __clobber_all);
507}
508
509SEC("tc")
510__description("helper access to variable memory: size = 0 allowed on != NULL map pointer (ARG_PTR_TO_MEM_OR_NULL)")
511__success __retval(0)
512__naked void ptr_to_mem_or_null_4(void)
513{
514	asm volatile ("					\
515	r1 = 0;						\
516	*(u64*)(r10 - 8) = r1;				\
517	r2 = r10;					\
518	r2 += -8;					\
519	r1 = %[map_hash_8b] ll;				\
520	call %[bpf_map_lookup_elem];			\
521	if r0 == 0 goto l0_%=;				\
522	r1 = r0;					\
523	r2 = 0;						\
524	r3 = 0;						\
525	r4 = 0;						\
526	r5 = 0;						\
527	call %[bpf_csum_diff];				\
528l0_%=:	exit;						\
529"	:
530	: __imm(bpf_csum_diff),
531	  __imm(bpf_map_lookup_elem),
532	  __imm_addr(map_hash_8b)
533	: __clobber_all);
534}
535
536SEC("tc")
537__description("helper access to variable memory: size possible = 0 allowed on != NULL stack pointer (ARG_PTR_TO_MEM_OR_NULL)")
538__success __retval(0)
539__naked void ptr_to_mem_or_null_5(void)
540{
541	asm volatile ("					\
542	r1 = 0;						\
543	*(u64*)(r10 - 8) = r1;				\
544	r2 = r10;					\
545	r2 += -8;					\
546	r1 = %[map_hash_8b] ll;				\
547	call %[bpf_map_lookup_elem];			\
548	if r0 == 0 goto l0_%=;				\
549	r2 = *(u64*)(r0 + 0);				\
550	if r2 > 8 goto l0_%=;				\
551	r1 = r10;					\
552	r1 += -8;					\
553	*(u64*)(r1 + 0) = r2;				\
554	r3 = 0;						\
555	r4 = 0;						\
556	r5 = 0;						\
557	call %[bpf_csum_diff];				\
558l0_%=:	exit;						\
559"	:
560	: __imm(bpf_csum_diff),
561	  __imm(bpf_map_lookup_elem),
562	  __imm_addr(map_hash_8b)
563	: __clobber_all);
564}
565
566SEC("tc")
567__description("helper access to variable memory: size possible = 0 allowed on != NULL map pointer (ARG_PTR_TO_MEM_OR_NULL)")
568__success __retval(0)
569__naked void ptr_to_mem_or_null_6(void)
570{
571	asm volatile ("					\
572	r1 = 0;						\
573	*(u64*)(r10 - 8) = r1;				\
574	r2 = r10;					\
575	r2 += -8;					\
576	r1 = %[map_hash_8b] ll;				\
577	call %[bpf_map_lookup_elem];			\
578	if r0 == 0 goto l0_%=;				\
579	r1 = r0;					\
580	r2 = *(u64*)(r0 + 0);				\
581	if r2 > 8 goto l0_%=;				\
582	r3 = 0;						\
583	r4 = 0;						\
584	r5 = 0;						\
585	call %[bpf_csum_diff];				\
586l0_%=:	exit;						\
587"	:
588	: __imm(bpf_csum_diff),
589	  __imm(bpf_map_lookup_elem),
590	  __imm_addr(map_hash_8b)
591	: __clobber_all);
592}
593
594SEC("tc")
595__description("helper access to variable memory: size possible = 0 allowed on != NULL packet pointer (ARG_PTR_TO_MEM_OR_NULL)")
596__success __retval(0)
597/* csum_diff of 64-byte packet */
598__flag(BPF_F_ANY_ALIGNMENT)
599__naked void ptr_to_mem_or_null_7(void)
600{
601	asm volatile ("					\
602	r6 = *(u32*)(r1 + %[__sk_buff_data]);		\
603	r3 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
604	r0 = r6;					\
605	r0 += 8;					\
606	if r0 > r3 goto l0_%=;				\
607	r1 = r6;					\
608	r2 = *(u64*)(r6 + 0);				\
609	if r2 > 8 goto l0_%=;				\
610	r3 = 0;						\
611	r4 = 0;						\
612	r5 = 0;						\
613	call %[bpf_csum_diff];				\
614l0_%=:	exit;						\
615"	:
616	: __imm(bpf_csum_diff),
617	  __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
618	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
619	: __clobber_all);
620}
621
622SEC("tracepoint")
623__description("helper access to variable memory: size = 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)")
624__failure __msg("R1 type=scalar expected=fp")
625__naked void ptr_to_mem_or_null_8(void)
626{
627	asm volatile ("					\
628	r1 = 0;						\
629	r2 = 0;						\
630	r3 = 0;						\
631	call %[bpf_probe_read_kernel];			\
632	exit;						\
633"	:
634	: __imm(bpf_probe_read_kernel)
635	: __clobber_all);
636}
637
638SEC("tracepoint")
639__description("helper access to variable memory: size > 0 not allowed on NULL (!ARG_PTR_TO_MEM_OR_NULL)")
640__failure __msg("R1 type=scalar expected=fp")
641__naked void ptr_to_mem_or_null_9(void)
642{
643	asm volatile ("					\
644	r1 = 0;						\
645	r2 = 1;						\
646	r3 = 0;						\
647	call %[bpf_probe_read_kernel];			\
648	exit;						\
649"	:
650	: __imm(bpf_probe_read_kernel)
651	: __clobber_all);
652}
653
654SEC("tracepoint")
655__description("helper access to variable memory: size = 0 allowed on != NULL stack pointer (!ARG_PTR_TO_MEM_OR_NULL)")
656__success
657__naked void ptr_to_mem_or_null_10(void)
658{
659	asm volatile ("					\
660	r1 = r10;					\
661	r1 += -8;					\
662	r2 = 0;						\
663	r3 = 0;						\
664	call %[bpf_probe_read_kernel];			\
665	exit;						\
666"	:
667	: __imm(bpf_probe_read_kernel)
668	: __clobber_all);
669}
670
671SEC("tracepoint")
672__description("helper access to variable memory: size = 0 allowed on != NULL map pointer (!ARG_PTR_TO_MEM_OR_NULL)")
673__success
674__naked void ptr_to_mem_or_null_11(void)
675{
676	asm volatile ("					\
677	r1 = 0;						\
678	*(u64*)(r10 - 8) = r1;				\
679	r2 = r10;					\
680	r2 += -8;					\
681	r1 = %[map_hash_8b] ll;				\
682	call %[bpf_map_lookup_elem];			\
683	if r0 == 0 goto l0_%=;				\
684	r1 = r0;					\
685	r2 = 0;						\
686	r3 = 0;						\
687	call %[bpf_probe_read_kernel];			\
688l0_%=:	exit;						\
689"	:
690	: __imm(bpf_map_lookup_elem),
691	  __imm(bpf_probe_read_kernel),
692	  __imm_addr(map_hash_8b)
693	: __clobber_all);
694}
695
696SEC("tracepoint")
697__description("helper access to variable memory: size possible = 0 allowed on != NULL stack pointer (!ARG_PTR_TO_MEM_OR_NULL)")
698__success
699__naked void ptr_to_mem_or_null_12(void)
700{
701	asm volatile ("					\
702	r1 = 0;						\
703	*(u64*)(r10 - 8) = r1;				\
704	r2 = r10;					\
705	r2 += -8;					\
706	r1 = %[map_hash_8b] ll;				\
707	call %[bpf_map_lookup_elem];			\
708	if r0 == 0 goto l0_%=;				\
709	r2 = *(u64*)(r0 + 0);				\
710	if r2 > 8 goto l0_%=;				\
711	r1 = r10;					\
712	r1 += -8;					\
713	r3 = 0;						\
714	call %[bpf_probe_read_kernel];			\
715l0_%=:	exit;						\
716"	:
717	: __imm(bpf_map_lookup_elem),
718	  __imm(bpf_probe_read_kernel),
719	  __imm_addr(map_hash_8b)
720	: __clobber_all);
721}
722
723SEC("tracepoint")
724__description("helper access to variable memory: size possible = 0 allowed on != NULL map pointer (!ARG_PTR_TO_MEM_OR_NULL)")
725__success
726__naked void ptr_to_mem_or_null_13(void)
727{
728	asm volatile ("					\
729	r1 = 0;						\
730	*(u64*)(r10 - 8) = r1;				\
731	r2 = r10;					\
732	r2 += -8;					\
733	r1 = %[map_hash_8b] ll;				\
734	call %[bpf_map_lookup_elem];			\
735	if r0 == 0 goto l0_%=;				\
736	r1 = r0;					\
737	r2 = *(u64*)(r0 + 0);				\
738	if r2 > 8 goto l0_%=;				\
739	r3 = 0;						\
740	call %[bpf_probe_read_kernel];			\
741l0_%=:	exit;						\
742"	:
743	: __imm(bpf_map_lookup_elem),
744	  __imm(bpf_probe_read_kernel),
745	  __imm_addr(map_hash_8b)
746	: __clobber_all);
747}
748
749SEC("socket")
750__description("helper access to variable memory: 8 bytes leak")
751/* in privileged mode reads from uninitialized stack locations are permitted */
752__success __failure_unpriv
753__msg_unpriv("invalid indirect read from stack R2 off -64+32 size 64")
754__retval(0)
755__naked void variable_memory_8_bytes_leak(void)
756{
757	asm volatile ("					\
758	/* set max stack size */			\
759	r6 = 0;						\
760	*(u64*)(r10 - 128) = r6;			\
761	/* set r3 to a random value */			\
762	call %[bpf_get_prandom_u32];			\
763	r3 = r0;					\
764	r1 = %[map_ringbuf] ll;				\
765	r2 = r10;					\
766	r2 += -64;					\
767	r0 = 0;						\
768	*(u64*)(r10 - 64) = r0;				\
769	*(u64*)(r10 - 56) = r0;				\
770	*(u64*)(r10 - 48) = r0;				\
771	*(u64*)(r10 - 40) = r0;				\
772	/* Note: fp[-32] left uninitialized */		\
773	*(u64*)(r10 - 24) = r0;				\
774	*(u64*)(r10 - 16) = r0;				\
775	*(u64*)(r10 - 8) = r0;				\
776	/* Limit r3 range to [1, 64] */			\
777	r3 &= 63;					\
778	r3 += 1;					\
779	r4 = 0;						\
780	/* Call bpf_ringbuf_output(), it is one of a few helper functions with\
781	 * ARG_CONST_SIZE_OR_ZERO parameter allowed in unpriv mode.\
782	 * For unpriv this should signal an error, because memory region [1, 64]\
783	 * at &fp[-64] is not fully initialized.	\
784	 */						\
785	call %[bpf_ringbuf_output];			\
786	r0 = 0;						\
787	exit;						\
788"	:
789	: __imm(bpf_get_prandom_u32),
790	  __imm(bpf_ringbuf_output),
791	  __imm_addr(map_ringbuf)
792	: __clobber_all);
793}
794
795SEC("tracepoint")
796__description("helper access to variable memory: 8 bytes no leak (init memory)")
797__success
798__naked void bytes_no_leak_init_memory(void)
799{
800	asm volatile ("					\
801	r1 = r10;					\
802	r0 = 0;						\
803	r0 = 0;						\
804	*(u64*)(r10 - 64) = r0;				\
805	*(u64*)(r10 - 56) = r0;				\
806	*(u64*)(r10 - 48) = r0;				\
807	*(u64*)(r10 - 40) = r0;				\
808	*(u64*)(r10 - 32) = r0;				\
809	*(u64*)(r10 - 24) = r0;				\
810	*(u64*)(r10 - 16) = r0;				\
811	*(u64*)(r10 - 8) = r0;				\
812	r1 += -64;					\
813	r2 = 0;						\
814	r2 &= 32;					\
815	r2 += 32;					\
816	r3 = 0;						\
817	call %[bpf_probe_read_kernel];			\
818	r1 = *(u64*)(r10 - 16);				\
819	exit;						\
820"	:
821	: __imm(bpf_probe_read_kernel)
822	: __clobber_all);
823}
824
825char _license[] SEC("license") = "GPL";
826