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>
17#include <stddef.h>
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;
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	{
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	},
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),
265			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
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) */
292			/* BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 8), */
293			BPF_MOV64_REG(BPF_REG_0, BPF_REG_2),
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),
422			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_delete_elem),
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),
435			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
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),
450			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
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),
466			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
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	},
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),
553			BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_delete_elem),
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	},
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	},
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),
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),
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	},
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	},
746};
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
764	map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 1024);
765	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{
774	int prog_fd, i, pass_cnt = 0, err_cnt = 0;
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
792		prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog,
793					prog_len * sizeof(struct bpf_insn),
794					"GPL", 0);
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);
801				err_cnt++;
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);
808				err_cnt++;
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);
814				err_cnt++;
815				goto fail;
816			}
817		}
818
819		pass_cnt++;
820		printf("OK\n");
821fail:
822		if (map_fd >= 0)
823			close(map_fd);
824		close(prog_fd);
825
826	}
827	printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, err_cnt);
828
829	return 0;
830}
831
832int main(void)
833{
834	return test();
835}
836