blob: 12f3780af73fa5b4ec60fc88ae683bae509926c3 [file] [log] [blame]
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -07001/*
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>
Alexei Starovoitov614cd3b2015-03-13 11:57:43 -070017#include <stddef.h>
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -070018#include "libbpf.h"
19
20#define MAX_INSNS 512
21#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
22
23struct 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
34static 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 },
212 {
Alexei Starovoitov32bf08a2014-10-20 14:54:57 -0700213 "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 },
223 {
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700224 "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),
Alexei Starovoitov7943c0f2014-11-13 17:36:50 -0800265 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700266 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) */
Daniel Borkmannf91fe172015-03-01 12:31:41 +0100292 /* BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 8), */
293 BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700294 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),
Alexei Starovoitov7943c0f2014-11-13 17:36:50 -0800422 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_delete_elem),
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700423 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),
Alexei Starovoitov7943c0f2014-11-13 17:36:50 -0800435 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700436 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),
Alexei Starovoitov7943c0f2014-11-13 17:36:50 -0800450 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700451 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),
Alexei Starovoitov7943c0f2014-11-13 17:36:50 -0800466 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700467 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 },
Alexei Starovoitovfd10c2e2014-09-29 18:50:02 -0700477 {
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),
Alexei Starovoitov7943c0f2014-11-13 17:36:50 -0800553 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_delete_elem),
Alexei Starovoitovfd10c2e2014-09-29 18:50:02 -0700554 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 },
Alexei Starovoitov342ded42014-10-28 15:11:42 -0700607 {
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 },
Alexei Starovoitov614cd3b2015-03-13 11:57:43 -0700646 {
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),
Alexei Starovoitovc2497392015-03-16 18:06:02 -0700661 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),
Alexei Starovoitov614cd3b2015-03-13 11:57:43 -0700670 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 },
Alexei Starovoitov725f9dc2015-04-15 16:19:33 -0700724 {
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 },
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700746};
747
748static 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
759static int create_map(void)
760{
761 long long key, value = 0;
762 int map_fd;
763
Alexei Starovoitov7943c0f2014-11-13 17:36:50 -0800764 map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 1024);
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700765 if (map_fd < 0) {
766 printf("failed to create map '%s'\n", strerror(errno));
767 }
768
769 return map_fd;
770}
771
772static int test(void)
773{
Alexei Starovoitov342ded42014-10-28 15:11:42 -0700774 int prog_fd, i, pass_cnt = 0, err_cnt = 0;
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700775
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
Daniel Borkmannf91fe172015-03-01 12:31:41 +0100792 prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog,
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700793 prog_len * sizeof(struct bpf_insn),
Alexei Starovoitovb896c4f2015-03-25 12:49:23 -0700794 "GPL", 0);
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700795
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);
Alexei Starovoitov342ded42014-10-28 15:11:42 -0700801 err_cnt++;
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700802 goto fail;
803 }
804 } else {
805 if (prog_fd >= 0) {
806 printf("FAIL\nunexpected success to load\n");
807 printf("%s", bpf_log_buf);
Alexei Starovoitov342ded42014-10-28 15:11:42 -0700808 err_cnt++;
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700809 goto fail;
810 }
811 if (strstr(bpf_log_buf, tests[i].errstr) == 0) {
812 printf("FAIL\nunexpected error message: %s",
813 bpf_log_buf);
Alexei Starovoitov342ded42014-10-28 15:11:42 -0700814 err_cnt++;
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700815 goto fail;
816 }
817 }
818
Alexei Starovoitov342ded42014-10-28 15:11:42 -0700819 pass_cnt++;
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700820 printf("OK\n");
821fail:
822 if (map_fd >= 0)
823 close(map_fd);
824 close(prog_fd);
825
826 }
Alexei Starovoitov342ded42014-10-28 15:11:42 -0700827 printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, err_cnt);
Alexei Starovoitov3c731eb2014-09-26 00:17:07 -0700828
829 return 0;
830}
831
832int main(void)
833{
834 return test();
835}