1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
3
4 #include <errno.h>
5 #include <string.h>
6 #include <linux/bpf.h>
7 #include <bpf/bpf_helpers.h>
8 #include "bpf_misc.h"
9
10 char _license[] SEC("license") = "GPL";
11
12 #define ITER_HELPERS \
13 __imm(bpf_iter_num_new), \
14 __imm(bpf_iter_num_next), \
15 __imm(bpf_iter_num_destroy)
16
17 SEC("?raw_tp")
18 __success
force_clang_to_emit_btf_for_externs(void * ctx)19 int force_clang_to_emit_btf_for_externs(void *ctx)
20 {
21 /* we need this as a workaround to enforce compiler emitting BTF
22 * information for bpf_iter_num_{new,next,destroy}() kfuncs,
23 * as, apparently, it doesn't emit it for symbols only referenced from
24 * assembly (or cleanup attribute, for that matter, as well)
25 */
26 bpf_repeat(0);
27
28 return 0;
29 }
30
31 SEC("?raw_tp")
32 __success
consume_first_item_only(void * ctx)33 int consume_first_item_only(void *ctx)
34 {
35 struct bpf_iter_num iter;
36
37 asm volatile (
38 /* create iterator */
39 "r1 = %[iter];"
40 "r2 = 0;"
41 "r3 = 1000;"
42 "call %[bpf_iter_num_new];"
43
44 /* consume first item */
45 "r1 = %[iter];"
46 "call %[bpf_iter_num_next];"
47
48 "if r0 == 0 goto +1;"
49 "r0 = *(u32 *)(r0 + 0);"
50
51 /* destroy iterator */
52 "r1 = %[iter];"
53 "call %[bpf_iter_num_destroy];"
54 :
55 : __imm_ptr(iter), ITER_HELPERS
56 : __clobber_common
57 );
58
59 return 0;
60 }
61
62 SEC("?raw_tp")
63 __failure __msg("R0 invalid mem access 'scalar'")
missing_null_check_fail(void * ctx)64 int missing_null_check_fail(void *ctx)
65 {
66 struct bpf_iter_num iter;
67
68 asm volatile (
69 /* create iterator */
70 "r1 = %[iter];"
71 "r2 = 0;"
72 "r3 = 1000;"
73 "call %[bpf_iter_num_new];"
74
75 /* consume first element */
76 "r1 = %[iter];"
77 "call %[bpf_iter_num_next];"
78
79 /* FAIL: deref with no NULL check */
80 "r1 = *(u32 *)(r0 + 0);"
81
82 /* destroy iterator */
83 "r1 = %[iter];"
84 "call %[bpf_iter_num_destroy];"
85 :
86 : __imm_ptr(iter), ITER_HELPERS
87 : __clobber_common
88 );
89
90 return 0;
91 }
92
93 SEC("?raw_tp")
94 __failure
95 __msg("invalid access to memory, mem_size=4 off=0 size=8")
96 __msg("R0 min value is outside of the allowed memory range")
wrong_sized_read_fail(void * ctx)97 int wrong_sized_read_fail(void *ctx)
98 {
99 struct bpf_iter_num iter;
100
101 asm volatile (
102 /* create iterator */
103 "r1 = %[iter];"
104 "r2 = 0;"
105 "r3 = 1000;"
106 "call %[bpf_iter_num_new];"
107
108 /* consume first element */
109 "r1 = %[iter];"
110 "call %[bpf_iter_num_next];"
111
112 "if r0 == 0 goto +1;"
113 /* FAIL: deref more than available 4 bytes */
114 "r0 = *(u64 *)(r0 + 0);"
115
116 /* destroy iterator */
117 "r1 = %[iter];"
118 "call %[bpf_iter_num_destroy];"
119 :
120 : __imm_ptr(iter), ITER_HELPERS
121 : __clobber_common
122 );
123
124 return 0;
125 }
126
127 SEC("?raw_tp")
128 __success __log_level(2)
__flag(BPF_F_TEST_STATE_FREQ)129 __flag(BPF_F_TEST_STATE_FREQ)
130 int simplest_loop(void *ctx)
131 {
132 struct bpf_iter_num iter;
133
134 asm volatile (
135 "r6 = 0;" /* init sum */
136
137 /* create iterator */
138 "r1 = %[iter];"
139 "r2 = 0;"
140 "r3 = 10;"
141 "call %[bpf_iter_num_new];"
142
143 "1:"
144 /* consume next item */
145 "r1 = %[iter];"
146 "call %[bpf_iter_num_next];"
147
148 "if r0 == 0 goto 2f;"
149 "r0 = *(u32 *)(r0 + 0);"
150 "r6 += r0;" /* accumulate sum */
151 "goto 1b;"
152
153 "2:"
154 /* destroy iterator */
155 "r1 = %[iter];"
156 "call %[bpf_iter_num_destroy];"
157 :
158 : __imm_ptr(iter), ITER_HELPERS
159 : __clobber_common, "r6"
160 );
161
162 return 0;
163 }
164