Commit | Line | Data |
---|---|---|
3c731eba AS |
1 | /* |
2 | * Testsuite for eBPF verifier | |
3 | * | |
4 | * Copyright (c) 2014 PLUMgrid, http://plumgrid.com | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of version 2 of the GNU General Public | |
8 | * License as published by the Free Software Foundation. | |
9 | */ | |
10 | #include <stdio.h> | |
11 | #include <unistd.h> | |
12 | #include <linux/bpf.h> | |
13 | #include <errno.h> | |
14 | #include <linux/unistd.h> | |
15 | #include <string.h> | |
16 | #include <linux/filter.h> | |
614cd3bd | 17 | #include <stddef.h> |
3c731eba AS |
18 | #include "libbpf.h" |
19 | ||
20 | #define MAX_INSNS 512 | |
21 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) | |
22 | ||
23 | struct bpf_test { | |
24 | const char *descr; | |
25 | struct bpf_insn insns[MAX_INSNS]; | |
26 | int fixup[32]; | |
27 | const char *errstr; | |
28 | enum { | |
29 | ACCEPT, | |
30 | REJECT | |
31 | } result; | |
32 | }; | |
33 | ||
34 | static struct bpf_test tests[] = { | |
35 | { | |
36 | "add+sub+mul", | |
37 | .insns = { | |
38 | BPF_MOV64_IMM(BPF_REG_1, 1), | |
39 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 2), | |
40 | BPF_MOV64_IMM(BPF_REG_2, 3), | |
41 | BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_2), | |
42 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -1), | |
43 | BPF_ALU64_IMM(BPF_MUL, BPF_REG_1, 3), | |
44 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | |
45 | BPF_EXIT_INSN(), | |
46 | }, | |
47 | .result = ACCEPT, | |
48 | }, | |
49 | { | |
50 | "unreachable", | |
51 | .insns = { | |
52 | BPF_EXIT_INSN(), | |
53 | BPF_EXIT_INSN(), | |
54 | }, | |
55 | .errstr = "unreachable", | |
56 | .result = REJECT, | |
57 | }, | |
58 | { | |
59 | "unreachable2", | |
60 | .insns = { | |
61 | BPF_JMP_IMM(BPF_JA, 0, 0, 1), | |
62 | BPF_JMP_IMM(BPF_JA, 0, 0, 0), | |
63 | BPF_EXIT_INSN(), | |
64 | }, | |
65 | .errstr = "unreachable", | |
66 | .result = REJECT, | |
67 | }, | |
68 | { | |
69 | "out of range jump", | |
70 | .insns = { | |
71 | BPF_JMP_IMM(BPF_JA, 0, 0, 1), | |
72 | BPF_EXIT_INSN(), | |
73 | }, | |
74 | .errstr = "jump out of range", | |
75 | .result = REJECT, | |
76 | }, | |
77 | { | |
78 | "out of range jump2", | |
79 | .insns = { | |
80 | BPF_JMP_IMM(BPF_JA, 0, 0, -2), | |
81 | BPF_EXIT_INSN(), | |
82 | }, | |
83 | .errstr = "jump out of range", | |
84 | .result = REJECT, | |
85 | }, | |
86 | { | |
87 | "test1 ld_imm64", | |
88 | .insns = { | |
89 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), | |
90 | BPF_LD_IMM64(BPF_REG_0, 0), | |
91 | BPF_LD_IMM64(BPF_REG_0, 0), | |
92 | BPF_LD_IMM64(BPF_REG_0, 1), | |
93 | BPF_LD_IMM64(BPF_REG_0, 1), | |
94 | BPF_MOV64_IMM(BPF_REG_0, 2), | |
95 | BPF_EXIT_INSN(), | |
96 | }, | |
97 | .errstr = "invalid BPF_LD_IMM insn", | |
98 | .result = REJECT, | |
99 | }, | |
100 | { | |
101 | "test2 ld_imm64", | |
102 | .insns = { | |
103 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), | |
104 | BPF_LD_IMM64(BPF_REG_0, 0), | |
105 | BPF_LD_IMM64(BPF_REG_0, 0), | |
106 | BPF_LD_IMM64(BPF_REG_0, 1), | |
107 | BPF_LD_IMM64(BPF_REG_0, 1), | |
108 | BPF_EXIT_INSN(), | |
109 | }, | |
110 | .errstr = "invalid BPF_LD_IMM insn", | |
111 | .result = REJECT, | |
112 | }, | |
113 | { | |
114 | "test3 ld_imm64", | |
115 | .insns = { | |
116 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), | |
117 | BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 0), | |
118 | BPF_LD_IMM64(BPF_REG_0, 0), | |
119 | BPF_LD_IMM64(BPF_REG_0, 0), | |
120 | BPF_LD_IMM64(BPF_REG_0, 1), | |
121 | BPF_LD_IMM64(BPF_REG_0, 1), | |
122 | BPF_EXIT_INSN(), | |
123 | }, | |
124 | .errstr = "invalid bpf_ld_imm64 insn", | |
125 | .result = REJECT, | |
126 | }, | |
127 | { | |
128 | "test4 ld_imm64", | |
129 | .insns = { | |
130 | BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 0), | |
131 | BPF_EXIT_INSN(), | |
132 | }, | |
133 | .errstr = "invalid bpf_ld_imm64 insn", | |
134 | .result = REJECT, | |
135 | }, | |
136 | { | |
137 | "test5 ld_imm64", | |
138 | .insns = { | |
139 | BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 0), | |
140 | }, | |
141 | .errstr = "invalid bpf_ld_imm64 insn", | |
142 | .result = REJECT, | |
143 | }, | |
144 | { | |
145 | "no bpf_exit", | |
146 | .insns = { | |
147 | BPF_ALU64_REG(BPF_MOV, BPF_REG_0, BPF_REG_2), | |
148 | }, | |
149 | .errstr = "jump out of range", | |
150 | .result = REJECT, | |
151 | }, | |
152 | { | |
153 | "loop (back-edge)", | |
154 | .insns = { | |
155 | BPF_JMP_IMM(BPF_JA, 0, 0, -1), | |
156 | BPF_EXIT_INSN(), | |
157 | }, | |
158 | .errstr = "back-edge", | |
159 | .result = REJECT, | |
160 | }, | |
161 | { | |
162 | "loop2 (back-edge)", | |
163 | .insns = { | |
164 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | |
165 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), | |
166 | BPF_MOV64_REG(BPF_REG_3, BPF_REG_0), | |
167 | BPF_JMP_IMM(BPF_JA, 0, 0, -4), | |
168 | BPF_EXIT_INSN(), | |
169 | }, | |
170 | .errstr = "back-edge", | |
171 | .result = REJECT, | |
172 | }, | |
173 | { | |
174 | "conditional loop", | |
175 | .insns = { | |
176 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | |
177 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), | |
178 | BPF_MOV64_REG(BPF_REG_3, BPF_REG_0), | |
179 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, -3), | |
180 | BPF_EXIT_INSN(), | |
181 | }, | |
182 | .errstr = "back-edge", | |
183 | .result = REJECT, | |
184 | }, | |
185 | { | |
186 | "read uninitialized register", | |
187 | .insns = { | |
188 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | |
189 | BPF_EXIT_INSN(), | |
190 | }, | |
191 | .errstr = "R2 !read_ok", | |
192 | .result = REJECT, | |
193 | }, | |
194 | { | |
195 | "read invalid register", | |
196 | .insns = { | |
197 | BPF_MOV64_REG(BPF_REG_0, -1), | |
198 | BPF_EXIT_INSN(), | |
199 | }, | |
200 | .errstr = "R15 is invalid", | |
201 | .result = REJECT, | |
202 | }, | |
203 | { | |
204 | "program doesn't init R0 before exit", | |
205 | .insns = { | |
206 | BPF_ALU64_REG(BPF_MOV, BPF_REG_2, BPF_REG_1), | |
207 | BPF_EXIT_INSN(), | |
208 | }, | |
209 | .errstr = "R0 !read_ok", | |
210 | .result = REJECT, | |
211 | }, | |
32bf08a6 AS |
212 | { |
213 | "program doesn't init R0 before exit in all branches", | |
214 | .insns = { | |
215 | BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), | |
216 | BPF_MOV64_IMM(BPF_REG_0, 1), | |
217 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 2), | |
218 | BPF_EXIT_INSN(), | |
219 | }, | |
220 | .errstr = "R0 !read_ok", | |
221 | .result = REJECT, | |
222 | }, | |
3c731eba AS |
223 | { |
224 | "stack out of bounds", | |
225 | .insns = { | |
226 | BPF_ST_MEM(BPF_DW, BPF_REG_10, 8, 0), | |
227 | BPF_EXIT_INSN(), | |
228 | }, | |
229 | .errstr = "invalid stack", | |
230 | .result = REJECT, | |
231 | }, | |
232 | { | |
233 | "invalid call insn1", | |
234 | .insns = { | |
235 | BPF_RAW_INSN(BPF_JMP | BPF_CALL | BPF_X, 0, 0, 0, 0), | |
236 | BPF_EXIT_INSN(), | |
237 | }, | |
238 | .errstr = "BPF_CALL uses reserved", | |
239 | .result = REJECT, | |
240 | }, | |
241 | { | |
242 | "invalid call insn2", | |
243 | .insns = { | |
244 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 1, 0), | |
245 | BPF_EXIT_INSN(), | |
246 | }, | |
247 | .errstr = "BPF_CALL uses reserved", | |
248 | .result = REJECT, | |
249 | }, | |
250 | { | |
251 | "invalid function call", | |
252 | .insns = { | |
253 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 1234567), | |
254 | BPF_EXIT_INSN(), | |
255 | }, | |
256 | .errstr = "invalid func 1234567", | |
257 | .result = REJECT, | |
258 | }, | |
259 | { | |
260 | "uninitialized stack1", | |
261 | .insns = { | |
262 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
263 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | |
264 | BPF_LD_MAP_FD(BPF_REG_1, 0), | |
7943c0f3 | 265 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
3c731eba AS |
266 | BPF_EXIT_INSN(), |
267 | }, | |
268 | .fixup = {2}, | |
269 | .errstr = "invalid indirect read from stack", | |
270 | .result = REJECT, | |
271 | }, | |
272 | { | |
273 | "uninitialized stack2", | |
274 | .insns = { | |
275 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
276 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, -8), | |
277 | BPF_EXIT_INSN(), | |
278 | }, | |
279 | .errstr = "invalid read from stack", | |
280 | .result = REJECT, | |
281 | }, | |
282 | { | |
283 | "check valid spill/fill", | |
284 | .insns = { | |
285 | /* spill R1(ctx) into stack */ | |
286 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8), | |
287 | ||
288 | /* fill it back into R2 */ | |
289 | BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -8), | |
290 | ||
291 | /* should be able to access R0 = *(R2 + 8) */ | |
f91fe17e DB |
292 | /* BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 8), */ |
293 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), | |
3c731eba AS |
294 | BPF_EXIT_INSN(), |
295 | }, | |
296 | .result = ACCEPT, | |
297 | }, | |
298 | { | |
299 | "check corrupted spill/fill", | |
300 | .insns = { | |
301 | /* spill R1(ctx) into stack */ | |
302 | BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8), | |
303 | ||
304 | /* mess up with R1 pointer on stack */ | |
305 | BPF_ST_MEM(BPF_B, BPF_REG_10, -7, 0x23), | |
306 | ||
307 | /* fill back into R0 should fail */ | |
308 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), | |
309 | ||
310 | BPF_EXIT_INSN(), | |
311 | }, | |
312 | .errstr = "corrupted spill", | |
313 | .result = REJECT, | |
314 | }, | |
315 | { | |
316 | "invalid src register in STX", | |
317 | .insns = { | |
318 | BPF_STX_MEM(BPF_B, BPF_REG_10, -1, -1), | |
319 | BPF_EXIT_INSN(), | |
320 | }, | |
321 | .errstr = "R15 is invalid", | |
322 | .result = REJECT, | |
323 | }, | |
324 | { | |
325 | "invalid dst register in STX", | |
326 | .insns = { | |
327 | BPF_STX_MEM(BPF_B, 14, BPF_REG_10, -1), | |
328 | BPF_EXIT_INSN(), | |
329 | }, | |
330 | .errstr = "R14 is invalid", | |
331 | .result = REJECT, | |
332 | }, | |
333 | { | |
334 | "invalid dst register in ST", | |
335 | .insns = { | |
336 | BPF_ST_MEM(BPF_B, 14, -1, -1), | |
337 | BPF_EXIT_INSN(), | |
338 | }, | |
339 | .errstr = "R14 is invalid", | |
340 | .result = REJECT, | |
341 | }, | |
342 | { | |
343 | "invalid src register in LDX", | |
344 | .insns = { | |
345 | BPF_LDX_MEM(BPF_B, BPF_REG_0, 12, 0), | |
346 | BPF_EXIT_INSN(), | |
347 | }, | |
348 | .errstr = "R12 is invalid", | |
349 | .result = REJECT, | |
350 | }, | |
351 | { | |
352 | "invalid dst register in LDX", | |
353 | .insns = { | |
354 | BPF_LDX_MEM(BPF_B, 11, BPF_REG_1, 0), | |
355 | BPF_EXIT_INSN(), | |
356 | }, | |
357 | .errstr = "R11 is invalid", | |
358 | .result = REJECT, | |
359 | }, | |
360 | { | |
361 | "junk insn", | |
362 | .insns = { | |
363 | BPF_RAW_INSN(0, 0, 0, 0, 0), | |
364 | BPF_EXIT_INSN(), | |
365 | }, | |
366 | .errstr = "invalid BPF_LD_IMM", | |
367 | .result = REJECT, | |
368 | }, | |
369 | { | |
370 | "junk insn2", | |
371 | .insns = { | |
372 | BPF_RAW_INSN(1, 0, 0, 0, 0), | |
373 | BPF_EXIT_INSN(), | |
374 | }, | |
375 | .errstr = "BPF_LDX uses reserved fields", | |
376 | .result = REJECT, | |
377 | }, | |
378 | { | |
379 | "junk insn3", | |
380 | .insns = { | |
381 | BPF_RAW_INSN(-1, 0, 0, 0, 0), | |
382 | BPF_EXIT_INSN(), | |
383 | }, | |
384 | .errstr = "invalid BPF_ALU opcode f0", | |
385 | .result = REJECT, | |
386 | }, | |
387 | { | |
388 | "junk insn4", | |
389 | .insns = { | |
390 | BPF_RAW_INSN(-1, -1, -1, -1, -1), | |
391 | BPF_EXIT_INSN(), | |
392 | }, | |
393 | .errstr = "invalid BPF_ALU opcode f0", | |
394 | .result = REJECT, | |
395 | }, | |
396 | { | |
397 | "junk insn5", | |
398 | .insns = { | |
399 | BPF_RAW_INSN(0x7f, -1, -1, -1, -1), | |
400 | BPF_EXIT_INSN(), | |
401 | }, | |
402 | .errstr = "BPF_ALU uses reserved fields", | |
403 | .result = REJECT, | |
404 | }, | |
405 | { | |
406 | "misaligned read from stack", | |
407 | .insns = { | |
408 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
409 | BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, -4), | |
410 | BPF_EXIT_INSN(), | |
411 | }, | |
412 | .errstr = "misaligned access", | |
413 | .result = REJECT, | |
414 | }, | |
415 | { | |
416 | "invalid map_fd for function call", | |
417 | .insns = { | |
418 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | |
419 | BPF_ALU64_REG(BPF_MOV, BPF_REG_2, BPF_REG_10), | |
420 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | |
421 | BPF_LD_MAP_FD(BPF_REG_1, 0), | |
7943c0f3 | 422 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_delete_elem), |
3c731eba AS |
423 | BPF_EXIT_INSN(), |
424 | }, | |
425 | .errstr = "fd 0 is not pointing to valid bpf_map", | |
426 | .result = REJECT, | |
427 | }, | |
428 | { | |
429 | "don't check return value before access", | |
430 | .insns = { | |
431 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | |
432 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
433 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | |
434 | BPF_LD_MAP_FD(BPF_REG_1, 0), | |
7943c0f3 | 435 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
3c731eba AS |
436 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), |
437 | BPF_EXIT_INSN(), | |
438 | }, | |
439 | .fixup = {3}, | |
440 | .errstr = "R0 invalid mem access 'map_value_or_null'", | |
441 | .result = REJECT, | |
442 | }, | |
443 | { | |
444 | "access memory with incorrect alignment", | |
445 | .insns = { | |
446 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | |
447 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
448 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | |
449 | BPF_LD_MAP_FD(BPF_REG_1, 0), | |
7943c0f3 | 450 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
3c731eba AS |
451 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), |
452 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 4, 0), | |
453 | BPF_EXIT_INSN(), | |
454 | }, | |
455 | .fixup = {3}, | |
456 | .errstr = "misaligned access", | |
457 | .result = REJECT, | |
458 | }, | |
459 | { | |
460 | "sometimes access memory with incorrect alignment", | |
461 | .insns = { | |
462 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | |
463 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
464 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | |
465 | BPF_LD_MAP_FD(BPF_REG_1, 0), | |
7943c0f3 | 466 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), |
3c731eba AS |
467 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), |
468 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), | |
469 | BPF_EXIT_INSN(), | |
470 | BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 1), | |
471 | BPF_EXIT_INSN(), | |
472 | }, | |
473 | .fixup = {3}, | |
474 | .errstr = "R0 invalid mem access", | |
475 | .result = REJECT, | |
476 | }, | |
fd10c2ef AS |
477 | { |
478 | "jump test 1", | |
479 | .insns = { | |
480 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
481 | BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -8), | |
482 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), | |
483 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 0), | |
484 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 1, 1), | |
485 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 1), | |
486 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 2, 1), | |
487 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 2), | |
488 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 3, 1), | |
489 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 3), | |
490 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 4, 1), | |
491 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 4), | |
492 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 5, 1), | |
493 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -32, 5), | |
494 | BPF_MOV64_IMM(BPF_REG_0, 0), | |
495 | BPF_EXIT_INSN(), | |
496 | }, | |
497 | .result = ACCEPT, | |
498 | }, | |
499 | { | |
500 | "jump test 2", | |
501 | .insns = { | |
502 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
503 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 2), | |
504 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 0), | |
505 | BPF_JMP_IMM(BPF_JA, 0, 0, 14), | |
506 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 1, 2), | |
507 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 0), | |
508 | BPF_JMP_IMM(BPF_JA, 0, 0, 11), | |
509 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 2, 2), | |
510 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -32, 0), | |
511 | BPF_JMP_IMM(BPF_JA, 0, 0, 8), | |
512 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 3, 2), | |
513 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -40, 0), | |
514 | BPF_JMP_IMM(BPF_JA, 0, 0, 5), | |
515 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 4, 2), | |
516 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -48, 0), | |
517 | BPF_JMP_IMM(BPF_JA, 0, 0, 2), | |
518 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 5, 1), | |
519 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -56, 0), | |
520 | BPF_MOV64_IMM(BPF_REG_0, 0), | |
521 | BPF_EXIT_INSN(), | |
522 | }, | |
523 | .result = ACCEPT, | |
524 | }, | |
525 | { | |
526 | "jump test 3", | |
527 | .insns = { | |
528 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
529 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 3), | |
530 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 0), | |
531 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | |
532 | BPF_JMP_IMM(BPF_JA, 0, 0, 19), | |
533 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 1, 3), | |
534 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 0), | |
535 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16), | |
536 | BPF_JMP_IMM(BPF_JA, 0, 0, 15), | |
537 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 2, 3), | |
538 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -32, 0), | |
539 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -32), | |
540 | BPF_JMP_IMM(BPF_JA, 0, 0, 11), | |
541 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 3, 3), | |
542 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -40, 0), | |
543 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -40), | |
544 | BPF_JMP_IMM(BPF_JA, 0, 0, 7), | |
545 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 4, 3), | |
546 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -48, 0), | |
547 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -48), | |
548 | BPF_JMP_IMM(BPF_JA, 0, 0, 3), | |
549 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 5, 0), | |
550 | BPF_ST_MEM(BPF_DW, BPF_REG_2, -56, 0), | |
551 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -56), | |
552 | BPF_LD_MAP_FD(BPF_REG_1, 0), | |
7943c0f3 | 553 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_delete_elem), |
fd10c2ef AS |
554 | BPF_EXIT_INSN(), |
555 | }, | |
556 | .fixup = {24}, | |
557 | .result = ACCEPT, | |
558 | }, | |
559 | { | |
560 | "jump test 4", | |
561 | .insns = { | |
562 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), | |
563 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), | |
564 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), | |
565 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), | |
566 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), | |
567 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), | |
568 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), | |
569 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), | |
570 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), | |
571 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), | |
572 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), | |
573 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), | |
574 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), | |
575 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), | |
576 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), | |
577 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), | |
578 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), | |
579 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), | |
580 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), | |
581 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), | |
582 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), | |
583 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), | |
584 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), | |
585 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), | |
586 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), | |
587 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), | |
588 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), | |
589 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), | |
590 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), | |
591 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), | |
592 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), | |
593 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), | |
594 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), | |
595 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), | |
596 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), | |
597 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), | |
598 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0), | |
599 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0), | |
600 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0), | |
601 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0), | |
602 | BPF_MOV64_IMM(BPF_REG_0, 0), | |
603 | BPF_EXIT_INSN(), | |
604 | }, | |
605 | .result = ACCEPT, | |
606 | }, | |
342ded40 AS |
607 | { |
608 | "jump test 5", | |
609 | .insns = { | |
610 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
611 | BPF_MOV64_REG(BPF_REG_3, BPF_REG_2), | |
612 | BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), | |
613 | BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8), | |
614 | BPF_JMP_IMM(BPF_JA, 0, 0, 2), | |
615 | BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8), | |
616 | BPF_JMP_IMM(BPF_JA, 0, 0, 0), | |
617 | BPF_MOV64_IMM(BPF_REG_0, 0), | |
618 | BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), | |
619 | BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8), | |
620 | BPF_JMP_IMM(BPF_JA, 0, 0, 2), | |
621 | BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8), | |
622 | BPF_JMP_IMM(BPF_JA, 0, 0, 0), | |
623 | BPF_MOV64_IMM(BPF_REG_0, 0), | |
624 | BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), | |
625 | BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8), | |
626 | BPF_JMP_IMM(BPF_JA, 0, 0, 2), | |
627 | BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8), | |
628 | BPF_JMP_IMM(BPF_JA, 0, 0, 0), | |
629 | BPF_MOV64_IMM(BPF_REG_0, 0), | |
630 | BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), | |
631 | BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8), | |
632 | BPF_JMP_IMM(BPF_JA, 0, 0, 2), | |
633 | BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8), | |
634 | BPF_JMP_IMM(BPF_JA, 0, 0, 0), | |
635 | BPF_MOV64_IMM(BPF_REG_0, 0), | |
636 | BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), | |
637 | BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8), | |
638 | BPF_JMP_IMM(BPF_JA, 0, 0, 2), | |
639 | BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8), | |
640 | BPF_JMP_IMM(BPF_JA, 0, 0, 0), | |
641 | BPF_MOV64_IMM(BPF_REG_0, 0), | |
642 | BPF_EXIT_INSN(), | |
643 | }, | |
644 | .result = ACCEPT, | |
645 | }, | |
614cd3bd AS |
646 | { |
647 | "access skb fields ok", | |
648 | .insns = { | |
649 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | |
650 | offsetof(struct __sk_buff, len)), | |
651 | BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1), | |
652 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | |
653 | offsetof(struct __sk_buff, mark)), | |
654 | BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1), | |
655 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | |
656 | offsetof(struct __sk_buff, pkt_type)), | |
657 | BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1), | |
658 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | |
659 | offsetof(struct __sk_buff, queue_mapping)), | |
660 | BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0), | |
c2497395 AS |
661 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, |
662 | offsetof(struct __sk_buff, protocol)), | |
663 | BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0), | |
664 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | |
665 | offsetof(struct __sk_buff, vlan_present)), | |
666 | BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0), | |
667 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | |
668 | offsetof(struct __sk_buff, vlan_tci)), | |
669 | BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0), | |
614cd3bd AS |
670 | BPF_EXIT_INSN(), |
671 | }, | |
672 | .result = ACCEPT, | |
673 | }, | |
674 | { | |
675 | "access skb fields bad1", | |
676 | .insns = { | |
677 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, -4), | |
678 | BPF_EXIT_INSN(), | |
679 | }, | |
680 | .errstr = "invalid bpf_context access", | |
681 | .result = REJECT, | |
682 | }, | |
683 | { | |
684 | "access skb fields bad2", | |
685 | .insns = { | |
686 | BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 9), | |
687 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | |
688 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
689 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | |
690 | BPF_LD_MAP_FD(BPF_REG_1, 0), | |
691 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), | |
692 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), | |
693 | BPF_EXIT_INSN(), | |
694 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | |
695 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | |
696 | offsetof(struct __sk_buff, pkt_type)), | |
697 | BPF_EXIT_INSN(), | |
698 | }, | |
699 | .fixup = {4}, | |
700 | .errstr = "different pointers", | |
701 | .result = REJECT, | |
702 | }, | |
703 | { | |
704 | "access skb fields bad3", | |
705 | .insns = { | |
706 | BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), | |
707 | BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, | |
708 | offsetof(struct __sk_buff, pkt_type)), | |
709 | BPF_EXIT_INSN(), | |
710 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | |
711 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
712 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | |
713 | BPF_LD_MAP_FD(BPF_REG_1, 0), | |
714 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), | |
715 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), | |
716 | BPF_EXIT_INSN(), | |
717 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | |
718 | BPF_JMP_IMM(BPF_JA, 0, 0, -12), | |
719 | }, | |
720 | .fixup = {6}, | |
721 | .errstr = "different pointers", | |
722 | .result = REJECT, | |
723 | }, | |
725f9dcd AS |
724 | { |
725 | "access skb fields bad4", | |
726 | .insns = { | |
727 | BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 3), | |
728 | BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, | |
729 | offsetof(struct __sk_buff, len)), | |
730 | BPF_MOV64_IMM(BPF_REG_0, 0), | |
731 | BPF_EXIT_INSN(), | |
732 | BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), | |
733 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | |
734 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), | |
735 | BPF_LD_MAP_FD(BPF_REG_1, 0), | |
736 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), | |
737 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), | |
738 | BPF_EXIT_INSN(), | |
739 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), | |
740 | BPF_JMP_IMM(BPF_JA, 0, 0, -13), | |
741 | }, | |
742 | .fixup = {7}, | |
743 | .errstr = "different pointers", | |
744 | .result = REJECT, | |
745 | }, | |
3c731eba AS |
746 | }; |
747 | ||
748 | static int probe_filter_length(struct bpf_insn *fp) | |
749 | { | |
750 | int len = 0; | |
751 | ||
752 | for (len = MAX_INSNS - 1; len > 0; --len) | |
753 | if (fp[len].code != 0 || fp[len].imm != 0) | |
754 | break; | |
755 | ||
756 | return len + 1; | |
757 | } | |
758 | ||
759 | static int create_map(void) | |
760 | { | |
761 | long long key, value = 0; | |
762 | int map_fd; | |
763 | ||
7943c0f3 | 764 | map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 1024); |
3c731eba AS |
765 | if (map_fd < 0) { |
766 | printf("failed to create map '%s'\n", strerror(errno)); | |
767 | } | |
768 | ||
769 | return map_fd; | |
770 | } | |
771 | ||
772 | static int test(void) | |
773 | { | |
342ded40 | 774 | int prog_fd, i, pass_cnt = 0, err_cnt = 0; |
3c731eba AS |
775 | |
776 | for (i = 0; i < ARRAY_SIZE(tests); i++) { | |
777 | struct bpf_insn *prog = tests[i].insns; | |
778 | int prog_len = probe_filter_length(prog); | |
779 | int *fixup = tests[i].fixup; | |
780 | int map_fd = -1; | |
781 | ||
782 | if (*fixup) { | |
783 | map_fd = create_map(); | |
784 | ||
785 | do { | |
786 | prog[*fixup].imm = map_fd; | |
787 | fixup++; | |
788 | } while (*fixup); | |
789 | } | |
790 | printf("#%d %s ", i, tests[i].descr); | |
791 | ||
f91fe17e | 792 | prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog, |
3c731eba | 793 | prog_len * sizeof(struct bpf_insn), |
b896c4f9 | 794 | "GPL", 0); |
3c731eba AS |
795 | |
796 | if (tests[i].result == ACCEPT) { | |
797 | if (prog_fd < 0) { | |
798 | printf("FAIL\nfailed to load prog '%s'\n", | |
799 | strerror(errno)); | |
800 | printf("%s", bpf_log_buf); | |
342ded40 | 801 | err_cnt++; |
3c731eba AS |
802 | goto fail; |
803 | } | |
804 | } else { | |
805 | if (prog_fd >= 0) { | |
806 | printf("FAIL\nunexpected success to load\n"); | |
807 | printf("%s", bpf_log_buf); | |
342ded40 | 808 | err_cnt++; |
3c731eba AS |
809 | goto fail; |
810 | } | |
811 | if (strstr(bpf_log_buf, tests[i].errstr) == 0) { | |
812 | printf("FAIL\nunexpected error message: %s", | |
813 | bpf_log_buf); | |
342ded40 | 814 | err_cnt++; |
3c731eba AS |
815 | goto fail; |
816 | } | |
817 | } | |
818 | ||
342ded40 | 819 | pass_cnt++; |
3c731eba AS |
820 | printf("OK\n"); |
821 | fail: | |
822 | if (map_fd >= 0) | |
823 | close(map_fd); | |
824 | close(prog_fd); | |
825 | ||
826 | } | |
342ded40 | 827 | printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, err_cnt); |
3c731eba AS |
828 | |
829 | return 0; | |
830 | } | |
831 | ||
832 | int main(void) | |
833 | { | |
834 | return test(); | |
835 | } |