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