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
11 struct test_val {
12 unsigned int index;
13 int foo[MAX_ENTRIES];
14 };
15
16 struct {
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
23 SEC("socket")
24 __description("PTR_TO_STACK store/load")
25 __success __success_unpriv __retval(0xfaceb00c)
ptr_to_stack_store_load(void)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
38 SEC("socket")
39 __description("PTR_TO_STACK store/load - bad alignment on off")
40 __failure __msg("misaligned stack access off (0x0; 0x0)+-8+2 size 8")
41 __failure_unpriv
load_bad_alignment_on_off(void)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
54 SEC("socket")
55 __description("PTR_TO_STACK store/load - bad alignment on reg")
56 __failure __msg("misaligned stack access off (0x0; 0x0)+-10+8 size 8")
57 __failure_unpriv
load_bad_alignment_on_reg(void)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
70 SEC("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")
load_out_of_bounds_low(void)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
86 SEC("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
load_out_of_bounds_high(void)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
102 SEC("socket")
103 __description("PTR_TO_STACK check high 1")
104 __success __success_unpriv __retval(42)
to_stack_check_high_1(void)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
117 SEC("socket")
118 __description("PTR_TO_STACK check high 2")
119 __success __success_unpriv __retval(42)
to_stack_check_high_2(void)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
131 SEC("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)
to_stack_check_high_3(void)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
148 SEC("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")
to_stack_check_high_4(void)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
164 SEC("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")
to_stack_check_high_5(void)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
182 SEC("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")
to_stack_check_high_6(void)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
201 SEC("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")
to_stack_check_high_7(void)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
221 SEC("socket")
222 __description("PTR_TO_STACK check low 1")
223 __success __success_unpriv __retval(42)
to_stack_check_low_1(void)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
236 SEC("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)
to_stack_check_low_2(void)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
253 SEC("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")
to_stack_check_low_3(void)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
269 SEC("socket")
270 __description("PTR_TO_STACK check low 4")
271 __failure __msg("math between fp pointer")
272 __failure_unpriv
to_stack_check_low_4(void)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
287 SEC("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")
to_stack_check_low_5(void)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
305 SEC("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")
to_stack_check_low_6(void)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
324 SEC("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")
to_stack_check_low_7(void)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
344 SEC("socket")
345 __description("PTR_TO_STACK mixed reg/k, 1")
346 __success __success_unpriv __retval(42)
stack_mixed_reg_k_1(void)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
361 SEC("socket")
362 __description("PTR_TO_STACK mixed reg/k, 2")
363 __success __success_unpriv __retval(42)
stack_mixed_reg_k_2(void)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
383 SEC("socket")
384 __description("PTR_TO_STACK mixed reg/k, 3")
385 __success __success_unpriv __retval(-3)
stack_mixed_reg_k_3(void)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
400 SEC("socket")
401 __description("PTR_TO_STACK reg")
402 __success __success_unpriv __retval(42)
ptr_to_stack_reg(void)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
416 SEC("socket")
417 __description("stack pointer arithmetic")
418 __success __success_unpriv __retval(0)
stack_pointer_arithmetic(void)419 __naked void stack_pointer_arithmetic(void)
420 {
421 asm volatile (" \
422 r1 = 4; \
423 goto l0_%=; \
424 l0_%=: 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
440 SEC("tc")
441 __description("store PTR_TO_STACK in R10 to array map using BPF_B")
442 __success __retval(42)
array_map_using_bpf_b(void)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; \
456 l0_%=: 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; \
476 l1_%=: r0 = 42; \
477 exit; \
478 " :
479 : __imm(bpf_map_lookup_elem),
480 __imm_addr(map_array_48b)
481 : __clobber_all);
482 }
483
484 char _license[] SEC("license") = "GPL";
485