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

source code of linux/tools/testing/selftests/bpf/progs/verifier_stack_ptr.c