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) |
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 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 | |
54 | SEC("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 | |
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" ) |
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 |
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) |
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) |
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) |
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" ) |
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" ) |
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" ) |
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" ) |
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) |
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) |
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" ) |
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 |
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" ) |
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" ) |
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" ) |
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) |
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) |
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) |
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) |
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) |
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) |
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 | |