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 | |
10 | struct test_val { |
11 | unsigned int index; |
12 | int foo[MAX_ENTRIES]; |
13 | }; |
14 | |
15 | struct { |
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 | |
22 | struct { |
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 | |
29 | struct { |
30 | __uint(type, BPF_MAP_TYPE_RINGBUF); |
31 | __uint(max_entries, 4096); |
32 | } map_ringbuf SEC(".maps" ); |
33 | |
34 | SEC("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]; \ |
59 | l0_%=: r0 = 0; \ |
60 | exit; \ |
61 | " : |
62 | : __imm(bpf_probe_read_kernel) |
63 | : __clobber_all); |
64 | } |
65 | |
66 | SEC("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 | |
101 | SEC("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]; \ |
117 | l0_%=: r0 = 0; \ |
118 | exit; \ |
119 | " : |
120 | : __imm(bpf_probe_read_kernel) |
121 | : __clobber_all); |
122 | } |
123 | |
124 | SEC("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]; \ |
149 | l0_%=: r0 = 0; \ |
150 | exit; \ |
151 | " : |
152 | : __imm(bpf_probe_read_kernel) |
153 | : __clobber_all); |
154 | } |
155 | |
156 | SEC("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]; \ |
181 | l0_%=: r0 = 0; \ |
182 | exit; \ |
183 | " : |
184 | : __imm(bpf_probe_read_kernel) |
185 | : __clobber_all); |
186 | } |
187 | |
188 | SEC("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]; \ |
205 | l0_%=: r0 = 0; \ |
206 | exit; \ |
207 | " : |
208 | : __imm(bpf_probe_read_kernel) |
209 | : __clobber_all); |
210 | } |
211 | |
212 | SEC("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]; \ |
228 | l0_%=: r0 = 0; \ |
229 | exit; \ |
230 | " : |
231 | : __imm(bpf_probe_read_kernel) |
232 | : __clobber_all); |
233 | } |
234 | |
235 | SEC("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]; \ |
252 | l0_%=: r0 = 0; \ |
253 | exit; \ |
254 | " : |
255 | : __imm(bpf_probe_read_kernel) |
256 | : __clobber_all); |
257 | } |
258 | |
259 | SEC("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]; \ |
286 | l0_%=: 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 | |
295 | SEC("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; \ |
310 | l0_%=: exit; \ |
311 | " : |
312 | : __imm(bpf_probe_read_kernel) |
313 | : __clobber_all); |
314 | } |
315 | |
316 | SEC("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]; \ |
338 | l1_%=: r0 = 0; \ |
339 | l0_%=: 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 | |
348 | SEC("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]; \ |
371 | l1_%=: r0 = 0; \ |
372 | l0_%=: 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 | |
381 | SEC("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]; \ |
404 | l1_%=: r0 = 0; \ |
405 | l0_%=: 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 | |
415 | SEC("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]; \ |
439 | l1_%=: r0 = 0; \ |
440 | l0_%=: 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 | |
449 | SEC("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 | |
467 | SEC("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 | |
488 | SEC("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 | |
509 | SEC("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]; \ |
528 | l0_%=: exit; \ |
529 | " : |
530 | : __imm(bpf_csum_diff), |
531 | __imm(bpf_map_lookup_elem), |
532 | __imm_addr(map_hash_8b) |
533 | : __clobber_all); |
534 | } |
535 | |
536 | SEC("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]; \ |
558 | l0_%=: exit; \ |
559 | " : |
560 | : __imm(bpf_csum_diff), |
561 | __imm(bpf_map_lookup_elem), |
562 | __imm_addr(map_hash_8b) |
563 | : __clobber_all); |
564 | } |
565 | |
566 | SEC("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]; \ |
586 | l0_%=: exit; \ |
587 | " : |
588 | : __imm(bpf_csum_diff), |
589 | __imm(bpf_map_lookup_elem), |
590 | __imm_addr(map_hash_8b) |
591 | : __clobber_all); |
592 | } |
593 | |
594 | SEC("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]; \ |
614 | l0_%=: 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 | |
622 | SEC("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 | |
638 | SEC("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 | |
654 | SEC("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 | |
671 | SEC("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]; \ |
688 | l0_%=: 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 | |
696 | SEC("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]; \ |
715 | l0_%=: 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 | |
723 | SEC("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]; \ |
741 | l0_%=: 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 | |
749 | SEC("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 | |
795 | SEC("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 | |
825 | char _license[] SEC("license" ) = "GPL" ; |
826 | |