1// SPDX-License-Identifier: GPL-2.0
2/* Converted from tools/testing/selftests/bpf/verifier/stack_ptr.c */
3
4#include <linux/bpf.h>
5#include <bpf/bpf_helpers.h>
6#include <limits.h>
7#include "bpf_misc.h"
8
9#define MAX_ENTRIES 11
10
11struct test_val {
12	unsigned int index;
13	int foo[MAX_ENTRIES];
14};
15
16struct {
17	__uint(type, BPF_MAP_TYPE_ARRAY);
18	__uint(max_entries, 1);
19	__type(key, int);
20	__type(value, struct test_val);
21} map_array_48b SEC(".maps");
22
23SEC("socket")
24__description("PTR_TO_STACK store/load")
25__success __success_unpriv __retval(0xfaceb00c)
26__naked void ptr_to_stack_store_load(void)
27{
28	asm volatile ("					\
29	r1 = r10;					\
30	r1 += -10;					\
31	r0 = 0xfaceb00c;				\
32	*(u64*)(r1 + 2) = r0;				\
33	r0 = *(u64*)(r1 + 2);				\
34	exit;						\
35"	::: __clobber_all);
36}
37
38SEC("socket")
39__description("PTR_TO_STACK store/load - bad alignment on off")
40__failure __msg("misaligned stack access off 0+-8+2 size 8")
41__failure_unpriv
42__naked void load_bad_alignment_on_off(void)
43{
44	asm volatile ("					\
45	r1 = r10;					\
46	r1 += -8;					\
47	r0 = 0xfaceb00c;				\
48	*(u64*)(r1 + 2) = r0;				\
49	r0 = *(u64*)(r1 + 2);				\
50	exit;						\
51"	::: __clobber_all);
52}
53
54SEC("socket")
55__description("PTR_TO_STACK store/load - bad alignment on reg")
56__failure __msg("misaligned stack access off 0+-10+8 size 8")
57__failure_unpriv
58__naked void load_bad_alignment_on_reg(void)
59{
60	asm volatile ("					\
61	r1 = r10;					\
62	r1 += -10;					\
63	r0 = 0xfaceb00c;				\
64	*(u64*)(r1 + 8) = r0;				\
65	r0 = *(u64*)(r1 + 8);				\
66	exit;						\
67"	::: __clobber_all);
68}
69
70SEC("socket")
71__description("PTR_TO_STACK store/load - out of bounds low")
72__failure __msg("invalid write to stack R1 off=-79992 size=8")
73__msg_unpriv("R1 stack pointer arithmetic goes out of range")
74__naked void load_out_of_bounds_low(void)
75{
76	asm volatile ("					\
77	r1 = r10;					\
78	r1 += -80000;					\
79	r0 = 0xfaceb00c;				\
80	*(u64*)(r1 + 8) = r0;				\
81	r0 = *(u64*)(r1 + 8);				\
82	exit;						\
83"	::: __clobber_all);
84}
85
86SEC("socket")
87__description("PTR_TO_STACK store/load - out of bounds high")
88__failure __msg("invalid write to stack R1 off=0 size=8")
89__failure_unpriv
90__naked void load_out_of_bounds_high(void)
91{
92	asm volatile ("					\
93	r1 = r10;					\
94	r1 += -8;					\
95	r0 = 0xfaceb00c;				\
96	*(u64*)(r1 + 8) = r0;				\
97	r0 = *(u64*)(r1 + 8);				\
98	exit;						\
99"	::: __clobber_all);
100}
101
102SEC("socket")
103__description("PTR_TO_STACK check high 1")
104__success __success_unpriv __retval(42)
105__naked void to_stack_check_high_1(void)
106{
107	asm volatile ("					\
108	r1 = r10;					\
109	r1 += -1;					\
110	r0 = 42;					\
111	*(u8*)(r1 + 0) = r0;				\
112	r0 = *(u8*)(r1 + 0);				\
113	exit;						\
114"	::: __clobber_all);
115}
116
117SEC("socket")
118__description("PTR_TO_STACK check high 2")
119__success __success_unpriv __retval(42)
120__naked void to_stack_check_high_2(void)
121{
122	asm volatile ("					\
123	r1 = r10;					\
124	r0 = 42;					\
125	*(u8*)(r1 - 1) = r0;				\
126	r0 = *(u8*)(r1 - 1);				\
127	exit;						\
128"	::: __clobber_all);
129}
130
131SEC("socket")
132__description("PTR_TO_STACK check high 3")
133__success __failure_unpriv
134__msg_unpriv("R1 stack pointer arithmetic goes out of range")
135__retval(42)
136__naked void to_stack_check_high_3(void)
137{
138	asm volatile ("					\
139	r1 = r10;					\
140	r1 += 0;					\
141	r0 = 42;					\
142	*(u8*)(r1 - 1) = r0;				\
143	r0 = *(u8*)(r1 - 1);				\
144	exit;						\
145"	::: __clobber_all);
146}
147
148SEC("socket")
149__description("PTR_TO_STACK check high 4")
150__failure __msg("invalid write to stack R1 off=0 size=1")
151__msg_unpriv("R1 stack pointer arithmetic goes out of range")
152__naked void to_stack_check_high_4(void)
153{
154	asm volatile ("					\
155	r1 = r10;					\
156	r1 += 0;					\
157	r0 = 42;					\
158	*(u8*)(r1 + 0) = r0;				\
159	r0 = *(u8*)(r1 + 0);				\
160	exit;						\
161"	::: __clobber_all);
162}
163
164SEC("socket")
165__description("PTR_TO_STACK check high 5")
166__failure __msg("invalid write to stack R1")
167__msg_unpriv("R1 stack pointer arithmetic goes out of range")
168__naked void to_stack_check_high_5(void)
169{
170	asm volatile ("					\
171	r1 = r10;					\
172	r1 += %[__imm_0];				\
173	r0 = 42;					\
174	*(u8*)(r1 + 0) = r0;				\
175	r0 = *(u8*)(r1 + 0);				\
176	exit;						\
177"	:
178	: __imm_const(__imm_0, (1 << 29) - 1)
179	: __clobber_all);
180}
181
182SEC("socket")
183__description("PTR_TO_STACK check high 6")
184__failure __msg("invalid write to stack")
185__msg_unpriv("R1 stack pointer arithmetic goes out of range")
186__naked void to_stack_check_high_6(void)
187{
188	asm volatile ("					\
189	r1 = r10;					\
190	r1 += %[__imm_0];				\
191	r0 = 42;					\
192	*(u8*)(r1 + %[shrt_max]) = r0;			\
193	r0 = *(u8*)(r1 + %[shrt_max]);			\
194	exit;						\
195"	:
196	: __imm_const(__imm_0, (1 << 29) - 1),
197	  __imm_const(shrt_max, SHRT_MAX)
198	: __clobber_all);
199}
200
201SEC("socket")
202__description("PTR_TO_STACK check high 7")
203__failure __msg("fp pointer offset")
204__msg_unpriv("R1 stack pointer arithmetic goes out of range")
205__naked void to_stack_check_high_7(void)
206{
207	asm volatile ("					\
208	r1 = r10;					\
209	r1 += %[__imm_0];				\
210	r1 += %[__imm_0];				\
211	r0 = 42;					\
212	*(u8*)(r1 + %[shrt_max]) = r0;			\
213	r0 = *(u8*)(r1 + %[shrt_max]);			\
214	exit;						\
215"	:
216	: __imm_const(__imm_0, (1 << 29) - 1),
217	  __imm_const(shrt_max, SHRT_MAX)
218	: __clobber_all);
219}
220
221SEC("socket")
222__description("PTR_TO_STACK check low 1")
223__success __success_unpriv __retval(42)
224__naked void to_stack_check_low_1(void)
225{
226	asm volatile ("					\
227	r1 = r10;					\
228	r1 += -512;					\
229	r0 = 42;					\
230	*(u8*)(r1 + 0) = r0;				\
231	r0 = *(u8*)(r1 + 0);				\
232	exit;						\
233"	::: __clobber_all);
234}
235
236SEC("socket")
237__description("PTR_TO_STACK check low 2")
238__success __failure_unpriv
239__msg_unpriv("R1 stack pointer arithmetic goes out of range")
240__retval(42)
241__naked void to_stack_check_low_2(void)
242{
243	asm volatile ("					\
244	r1 = r10;					\
245	r1 += -513;					\
246	r0 = 42;					\
247	*(u8*)(r1 + 1) = r0;				\
248	r0 = *(u8*)(r1 + 1);				\
249	exit;						\
250"	::: __clobber_all);
251}
252
253SEC("socket")
254__description("PTR_TO_STACK check low 3")
255__failure __msg("invalid write to stack R1 off=-513 size=1")
256__msg_unpriv("R1 stack pointer arithmetic goes out of range")
257__naked void to_stack_check_low_3(void)
258{
259	asm volatile ("					\
260	r1 = r10;					\
261	r1 += -513;					\
262	r0 = 42;					\
263	*(u8*)(r1 + 0) = r0;				\
264	r0 = *(u8*)(r1 + 0);				\
265	exit;						\
266"	::: __clobber_all);
267}
268
269SEC("socket")
270__description("PTR_TO_STACK check low 4")
271__failure __msg("math between fp pointer")
272__failure_unpriv
273__naked void to_stack_check_low_4(void)
274{
275	asm volatile ("					\
276	r1 = r10;					\
277	r1 += %[int_min];				\
278	r0 = 42;					\
279	*(u8*)(r1 + 0) = r0;				\
280	r0 = *(u8*)(r1 + 0);				\
281	exit;						\
282"	:
283	: __imm_const(int_min, INT_MIN)
284	: __clobber_all);
285}
286
287SEC("socket")
288__description("PTR_TO_STACK check low 5")
289__failure __msg("invalid write to stack")
290__msg_unpriv("R1 stack pointer arithmetic goes out of range")
291__naked void to_stack_check_low_5(void)
292{
293	asm volatile ("					\
294	r1 = r10;					\
295	r1 += %[__imm_0];				\
296	r0 = 42;					\
297	*(u8*)(r1 + 0) = r0;				\
298	r0 = *(u8*)(r1 + 0);				\
299	exit;						\
300"	:
301	: __imm_const(__imm_0, -((1 << 29) - 1))
302	: __clobber_all);
303}
304
305SEC("socket")
306__description("PTR_TO_STACK check low 6")
307__failure __msg("invalid write to stack")
308__msg_unpriv("R1 stack pointer arithmetic goes out of range")
309__naked void to_stack_check_low_6(void)
310{
311	asm volatile ("					\
312	r1 = r10;					\
313	r1 += %[__imm_0];				\
314	r0 = 42;					\
315	*(u8*)(r1  %[shrt_min]) = r0;			\
316	r0 = *(u8*)(r1  %[shrt_min]);			\
317	exit;						\
318"	:
319	: __imm_const(__imm_0, -((1 << 29) - 1)),
320	  __imm_const(shrt_min, SHRT_MIN)
321	: __clobber_all);
322}
323
324SEC("socket")
325__description("PTR_TO_STACK check low 7")
326__failure __msg("fp pointer offset")
327__msg_unpriv("R1 stack pointer arithmetic goes out of range")
328__naked void to_stack_check_low_7(void)
329{
330	asm volatile ("					\
331	r1 = r10;					\
332	r1 += %[__imm_0];				\
333	r1 += %[__imm_0];				\
334	r0 = 42;					\
335	*(u8*)(r1  %[shrt_min]) = r0;			\
336	r0 = *(u8*)(r1  %[shrt_min]);			\
337	exit;						\
338"	:
339	: __imm_const(__imm_0, -((1 << 29) - 1)),
340	  __imm_const(shrt_min, SHRT_MIN)
341	: __clobber_all);
342}
343
344SEC("socket")
345__description("PTR_TO_STACK mixed reg/k, 1")
346__success __success_unpriv __retval(42)
347__naked void stack_mixed_reg_k_1(void)
348{
349	asm volatile ("					\
350	r1 = r10;					\
351	r1 += -3;					\
352	r2 = -3;					\
353	r1 += r2;					\
354	r0 = 42;					\
355	*(u8*)(r1 + 0) = r0;				\
356	r0 = *(u8*)(r1 + 0);				\
357	exit;						\
358"	::: __clobber_all);
359}
360
361SEC("socket")
362__description("PTR_TO_STACK mixed reg/k, 2")
363__success __success_unpriv __retval(42)
364__naked void stack_mixed_reg_k_2(void)
365{
366	asm volatile ("					\
367	r0 = 0;						\
368	*(u64*)(r10 - 8) = r0;				\
369	r0 = 0;						\
370	*(u64*)(r10 - 16) = r0;				\
371	r1 = r10;					\
372	r1 += -3;					\
373	r2 = -3;					\
374	r1 += r2;					\
375	r0 = 42;					\
376	*(u8*)(r1 + 0) = r0;				\
377	r5 = r10;					\
378	r0 = *(u8*)(r5 - 6);				\
379	exit;						\
380"	::: __clobber_all);
381}
382
383SEC("socket")
384__description("PTR_TO_STACK mixed reg/k, 3")
385__success __success_unpriv __retval(-3)
386__naked void stack_mixed_reg_k_3(void)
387{
388	asm volatile ("					\
389	r1 = r10;					\
390	r1 += -3;					\
391	r2 = -3;					\
392	r1 += r2;					\
393	r0 = 42;					\
394	*(u8*)(r1 + 0) = r0;				\
395	r0 = r2;					\
396	exit;						\
397"	::: __clobber_all);
398}
399
400SEC("socket")
401__description("PTR_TO_STACK reg")
402__success __success_unpriv __retval(42)
403__naked void ptr_to_stack_reg(void)
404{
405	asm volatile ("					\
406	r1 = r10;					\
407	r2 = -3;					\
408	r1 += r2;					\
409	r0 = 42;					\
410	*(u8*)(r1 + 0) = r0;				\
411	r0 = *(u8*)(r1 + 0);				\
412	exit;						\
413"	::: __clobber_all);
414}
415
416SEC("socket")
417__description("stack pointer arithmetic")
418__success __success_unpriv __retval(0)
419__naked void stack_pointer_arithmetic(void)
420{
421	asm volatile ("					\
422	r1 = 4;						\
423	goto l0_%=;					\
424l0_%=:	r7 = r10;					\
425	r7 += -10;					\
426	r7 += -10;					\
427	r2 = r7;					\
428	r2 += r1;					\
429	r0 = 0;						\
430	*(u32*)(r2 + 4) = r0;				\
431	r2 = r7;					\
432	r2 += 8;					\
433	r0 = 0;						\
434	*(u32*)(r2 + 4) = r0;				\
435	r0 = 0;						\
436	exit;						\
437"	::: __clobber_all);
438}
439
440SEC("tc")
441__description("store PTR_TO_STACK in R10 to array map using BPF_B")
442__success __retval(42)
443__naked void array_map_using_bpf_b(void)
444{
445	asm volatile ("					\
446	/* Load pointer to map. */			\
447	r2 = r10;					\
448	r2 += -8;					\
449	r1 = 0;						\
450	*(u64*)(r2 + 0) = r1;				\
451	r1 = %[map_array_48b] ll;			\
452	call %[bpf_map_lookup_elem];			\
453	if r0 != 0 goto l0_%=;				\
454	r0 = 2;						\
455	exit;						\
456l0_%=:	r1 = r0;					\
457	/* Copy R10 to R9. */				\
458	r9 = r10;					\
459	/* Pollute other registers with unaligned values. */\
460	r2 = -1;					\
461	r3 = -1;					\
462	r4 = -1;					\
463	r5 = -1;					\
464	r6 = -1;					\
465	r7 = -1;					\
466	r8 = -1;					\
467	/* Store both R9 and R10 with BPF_B and read back. */\
468	*(u8*)(r1 + 0) = r10;				\
469	r2 = *(u8*)(r1 + 0);				\
470	*(u8*)(r1 + 0) = r9;				\
471	r3 = *(u8*)(r1 + 0);				\
472	/* Should read back as same value. */		\
473	if r2 == r3 goto l1_%=;				\
474	r0 = 1;						\
475	exit;						\
476l1_%=:	r0 = 42;					\
477	exit;						\
478"	:
479	: __imm(bpf_map_lookup_elem),
480	  __imm_addr(map_array_48b)
481	: __clobber_all);
482}
483
484char _license[] SEC("license") = "GPL";
485