xref: /linux/tools/testing/selftests/bpf/verifier/bpf_loop_inline.c (revision 71dfa617ea9f18e4585fe78364217cd32b1fc382)
1 #define BTF_TYPES \
2 	.btf_strings = "\0int\0i\0ctx\0callback\0main\0", \
3 	.btf_types = { \
4 	/* 1: int   */ BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), \
5 	/* 2: int*  */ BTF_PTR_ENC(1), \
6 	/* 3: void* */ BTF_PTR_ENC(0), \
7 	/* 4: int __(void*) */ BTF_FUNC_PROTO_ENC(1, 1), \
8 		BTF_FUNC_PROTO_ARG_ENC(7, 3), \
9 	/* 5: int __(int, int*) */ BTF_FUNC_PROTO_ENC(1, 2), \
10 		BTF_FUNC_PROTO_ARG_ENC(5, 1), \
11 		BTF_FUNC_PROTO_ARG_ENC(7, 2), \
12 	/* 6: main      */ BTF_FUNC_ENC(20, 4), \
13 	/* 7: callback  */ BTF_FUNC_ENC(11, 5), \
14 	BTF_END_RAW \
15 	}
16 
17 #define MAIN_TYPE	6
18 #define CALLBACK_TYPE	7
19 
20 /* can't use BPF_CALL_REL, jit_subprogs adjusts IMM & OFF
21  * fields for pseudo calls
22  */
23 #define PSEUDO_CALL_INSN() \
24 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_CALL, \
25 		     INSN_OFF_MASK, INSN_IMM_MASK)
26 
27 /* can't use BPF_FUNC_loop constant,
28  * do_mix_fixups adjusts the IMM field
29  */
30 #define HELPER_CALL_INSN() \
31 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, INSN_OFF_MASK, INSN_IMM_MASK)
32 
33 {
34 	"inline simple bpf_loop call",
35 	.insns = {
36 	/* main */
37 	/* force verifier state branching to verify logic on first and
38 	 * subsequent bpf_loop insn processing steps
39 	 */
40 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_jiffies64),
41 	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 777, 2),
42 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_1, 1),
43 	BPF_JMP_IMM(BPF_JA, 0, 0, 1),
44 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_1, 2),
45 
46 	BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, BPF_REG_2, BPF_PSEUDO_FUNC, 0, 6),
47 	BPF_RAW_INSN(0, 0, 0, 0, 0),
48 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_3, 0),
49 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_4, 0),
50 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_loop),
51 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0),
52 	BPF_EXIT_INSN(),
53 	/* callback */
54 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 1),
55 	BPF_EXIT_INSN(),
56 	},
57 	.expected_insns = { PSEUDO_CALL_INSN() },
58 	.unexpected_insns = { HELPER_CALL_INSN() },
59 	.prog_type = BPF_PROG_TYPE_TRACEPOINT,
60 	.flags = F_NEEDS_JIT_ENABLED,
61 	.result = ACCEPT,
62 	.runs = 0,
63 	.func_info = { { 0, MAIN_TYPE }, { 12, CALLBACK_TYPE } },
64 	.func_info_cnt = 2,
65 	BTF_TYPES
66 },
67 {
68 	"don't inline bpf_loop call, flags non-zero",
69 	.insns = {
70 	/* main */
71 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_jiffies64),
72 	BPF_ALU64_REG(BPF_MOV, BPF_REG_6, BPF_REG_0),
73 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_jiffies64),
74 	BPF_ALU64_REG(BPF_MOV, BPF_REG_7, BPF_REG_0),
75 	BPF_JMP_IMM(BPF_JNE, BPF_REG_6, 0, 9),
76 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_4, 0),
77 	BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0, 0),
78 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_1, 1),
79 	BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, BPF_REG_2, BPF_PSEUDO_FUNC, 0, 7),
80 	BPF_RAW_INSN(0, 0, 0, 0, 0),
81 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_3, 0),
82 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_loop),
83 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0),
84 	BPF_EXIT_INSN(),
85 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_4, 1),
86 	BPF_JMP_IMM(BPF_JA, 0, 0, -10),
87 	/* callback */
88 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 1),
89 	BPF_EXIT_INSN(),
90 	},
91 	.expected_insns = { HELPER_CALL_INSN() },
92 	.unexpected_insns = { PSEUDO_CALL_INSN() },
93 	.prog_type = BPF_PROG_TYPE_TRACEPOINT,
94 	.flags = F_NEEDS_JIT_ENABLED,
95 	.result = ACCEPT,
96 	.runs = 0,
97 	.func_info = { { 0, MAIN_TYPE }, { 16, CALLBACK_TYPE } },
98 	.func_info_cnt = 2,
99 	BTF_TYPES
100 },
101 {
102 	"don't inline bpf_loop call, callback non-constant",
103 	.insns = {
104 	/* main */
105 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_jiffies64),
106 	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 777, 4), /* pick a random callback */
107 
108 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_1, 1),
109 	BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, BPF_REG_2, BPF_PSEUDO_FUNC, 0, 10),
110 	BPF_RAW_INSN(0, 0, 0, 0, 0),
111 	BPF_JMP_IMM(BPF_JA, 0, 0, 3),
112 
113 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_1, 1),
114 	BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, BPF_REG_2, BPF_PSEUDO_FUNC, 0, 8),
115 	BPF_RAW_INSN(0, 0, 0, 0, 0),
116 
117 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_3, 0),
118 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_4, 0),
119 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_loop),
120 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0),
121 	BPF_EXIT_INSN(),
122 	/* callback */
123 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 1),
124 	BPF_EXIT_INSN(),
125 	/* callback #2 */
126 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 1),
127 	BPF_EXIT_INSN(),
128 	},
129 	.expected_insns = { HELPER_CALL_INSN() },
130 	.unexpected_insns = { PSEUDO_CALL_INSN() },
131 	.prog_type = BPF_PROG_TYPE_TRACEPOINT,
132 	.flags = F_NEEDS_JIT_ENABLED,
133 	.result = ACCEPT,
134 	.runs = 0,
135 	.func_info = {
136 		{ 0, MAIN_TYPE },
137 		{ 14, CALLBACK_TYPE },
138 		{ 16, CALLBACK_TYPE }
139 	},
140 	.func_info_cnt = 3,
141 	BTF_TYPES
142 },
143 {
144 	"bpf_loop_inline and a dead func",
145 	.insns = {
146 	/* main */
147 
148 	/* A reference to callback #1 to make verifier count it as a func.
149 	 * This reference is overwritten below and callback #1 is dead.
150 	 */
151 	BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, BPF_REG_2, BPF_PSEUDO_FUNC, 0, 9),
152 	BPF_RAW_INSN(0, 0, 0, 0, 0),
153 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_1, 1),
154 	BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, BPF_REG_2, BPF_PSEUDO_FUNC, 0, 8),
155 	BPF_RAW_INSN(0, 0, 0, 0, 0),
156 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_3, 0),
157 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_4, 0),
158 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_loop),
159 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0),
160 	BPF_EXIT_INSN(),
161 	/* callback */
162 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 1),
163 	BPF_EXIT_INSN(),
164 	/* callback #2 */
165 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 1),
166 	BPF_EXIT_INSN(),
167 	},
168 	.expected_insns = { PSEUDO_CALL_INSN() },
169 	.unexpected_insns = { HELPER_CALL_INSN() },
170 	.prog_type = BPF_PROG_TYPE_TRACEPOINT,
171 	.flags = F_NEEDS_JIT_ENABLED,
172 	.result = ACCEPT,
173 	.runs = 0,
174 	.func_info = {
175 		{ 0, MAIN_TYPE },
176 		{ 10, CALLBACK_TYPE },
177 		{ 12, CALLBACK_TYPE }
178 	},
179 	.func_info_cnt = 3,
180 	BTF_TYPES
181 },
182 {
183 	"bpf_loop_inline stack locations for loop vars",
184 	.insns = {
185 	/* main */
186 	BPF_ST_MEM(BPF_W, BPF_REG_10, -12, 0x77),
187 	/* bpf_loop call #1 */
188 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_1, 1),
189 	BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, BPF_REG_2, BPF_PSEUDO_FUNC, 0, 22),
190 	BPF_RAW_INSN(0, 0, 0, 0, 0),
191 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_3, 0),
192 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_4, 0),
193 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_loop),
194 	/* bpf_loop call #2 */
195 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_1, 2),
196 	BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, BPF_REG_2, BPF_PSEUDO_FUNC, 0, 16),
197 	BPF_RAW_INSN(0, 0, 0, 0, 0),
198 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_3, 0),
199 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_4, 0),
200 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_loop),
201 	/* call func and exit */
202 	BPF_CALL_REL(2),
203 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0),
204 	BPF_EXIT_INSN(),
205 	/* func */
206 	BPF_ST_MEM(BPF_DW, BPF_REG_10, -32, 0x55),
207 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_1, 2),
208 	BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, BPF_REG_2, BPF_PSEUDO_FUNC, 0, 6),
209 	BPF_RAW_INSN(0, 0, 0, 0, 0),
210 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_3, 0),
211 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_4, 0),
212 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_loop),
213 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0),
214 	BPF_EXIT_INSN(),
215 	/* callback */
216 	BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 1),
217 	BPF_EXIT_INSN(),
218 	},
219 	.expected_insns = {
220 	BPF_ST_MEM(BPF_W, BPF_REG_10, -12, 0x77),
221 	SKIP_INSNS(),
222 	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_6, -40),
223 	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_7, -32),
224 	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_8, -24),
225 	SKIP_INSNS(),
226 	/* offsets are the same as in the first call */
227 	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_6, -40),
228 	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_7, -32),
229 	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_8, -24),
230 	SKIP_INSNS(),
231 	BPF_ST_MEM(BPF_DW, BPF_REG_10, -32, 0x55),
232 	SKIP_INSNS(),
233 	/* offsets differ from main because of different offset
234 	 * in BPF_ST_MEM instruction
235 	 */
236 	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_6, -56),
237 	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_7, -48),
238 	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_8, -40),
239 	},
240 	.unexpected_insns = { HELPER_CALL_INSN() },
241 	.prog_type = BPF_PROG_TYPE_TRACEPOINT,
242 	.flags = F_NEEDS_JIT_ENABLED,
243 	.result = ACCEPT,
244 	.func_info = {
245 		{ 0, MAIN_TYPE },
246 		{ 16, MAIN_TYPE },
247 		{ 25, CALLBACK_TYPE },
248 	},
249 	.func_info_cnt = 3,
250 	BTF_TYPES
251 },
252 {
253 	"inline bpf_loop call in a big program",
254 	.insns = {},
255 	.fill_helper = bpf_fill_big_prog_with_loop_1,
256 	.expected_insns = { PSEUDO_CALL_INSN() },
257 	.unexpected_insns = { HELPER_CALL_INSN() },
258 	.result = ACCEPT,
259 	.prog_type = BPF_PROG_TYPE_TRACEPOINT,
260 	.flags = F_NEEDS_JIT_ENABLED,
261 	.func_info = { { 0, MAIN_TYPE }, { 16, CALLBACK_TYPE } },
262 	.func_info_cnt = 2,
263 	BTF_TYPES
264 },
265 
266 #undef HELPER_CALL_INSN
267 #undef PSEUDO_CALL_INSN
268 #undef CALLBACK_TYPE
269 #undef MAIN_TYPE
270 #undef BTF_TYPES
271