xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/bpf/prog_tests/align.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <test_progs.h>
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #define MAX_INSNS	512
5*4882a593Smuzhiyun #define MAX_MATCHES	16
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun struct bpf_reg_match {
8*4882a593Smuzhiyun 	unsigned int line;
9*4882a593Smuzhiyun 	const char *match;
10*4882a593Smuzhiyun };
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun struct bpf_align_test {
13*4882a593Smuzhiyun 	const char *descr;
14*4882a593Smuzhiyun 	struct bpf_insn	insns[MAX_INSNS];
15*4882a593Smuzhiyun 	enum {
16*4882a593Smuzhiyun 		UNDEF,
17*4882a593Smuzhiyun 		ACCEPT,
18*4882a593Smuzhiyun 		REJECT
19*4882a593Smuzhiyun 	} result;
20*4882a593Smuzhiyun 	enum bpf_prog_type prog_type;
21*4882a593Smuzhiyun 	/* Matches must be in order of increasing line */
22*4882a593Smuzhiyun 	struct bpf_reg_match matches[MAX_MATCHES];
23*4882a593Smuzhiyun };
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun static struct bpf_align_test tests[] = {
26*4882a593Smuzhiyun 	/* Four tests of known constants.  These aren't staggeringly
27*4882a593Smuzhiyun 	 * interesting since we track exact values now.
28*4882a593Smuzhiyun 	 */
29*4882a593Smuzhiyun 	{
30*4882a593Smuzhiyun 		.descr = "mov",
31*4882a593Smuzhiyun 		.insns = {
32*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_3, 2),
33*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_3, 4),
34*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_3, 8),
35*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_3, 16),
36*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_3, 32),
37*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_0, 0),
38*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
39*4882a593Smuzhiyun 		},
40*4882a593Smuzhiyun 		.prog_type = BPF_PROG_TYPE_SCHED_CLS,
41*4882a593Smuzhiyun 		.matches = {
42*4882a593Smuzhiyun 			{1, "R1=ctx(id=0,off=0,imm=0)"},
43*4882a593Smuzhiyun 			{1, "R10=fp0"},
44*4882a593Smuzhiyun 			{1, "R3_w=inv2"},
45*4882a593Smuzhiyun 			{2, "R3_w=inv4"},
46*4882a593Smuzhiyun 			{3, "R3_w=inv8"},
47*4882a593Smuzhiyun 			{4, "R3_w=inv16"},
48*4882a593Smuzhiyun 			{5, "R3_w=inv32"},
49*4882a593Smuzhiyun 		},
50*4882a593Smuzhiyun 	},
51*4882a593Smuzhiyun 	{
52*4882a593Smuzhiyun 		.descr = "shift",
53*4882a593Smuzhiyun 		.insns = {
54*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_3, 1),
55*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
56*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
57*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
58*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
59*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_RSH, BPF_REG_3, 4),
60*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_4, 32),
61*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
62*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
63*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
64*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
65*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_0, 0),
66*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
67*4882a593Smuzhiyun 		},
68*4882a593Smuzhiyun 		.prog_type = BPF_PROG_TYPE_SCHED_CLS,
69*4882a593Smuzhiyun 		.matches = {
70*4882a593Smuzhiyun 			{1, "R1=ctx(id=0,off=0,imm=0)"},
71*4882a593Smuzhiyun 			{1, "R10=fp0"},
72*4882a593Smuzhiyun 			{1, "R3_w=inv1"},
73*4882a593Smuzhiyun 			{2, "R3_w=inv2"},
74*4882a593Smuzhiyun 			{3, "R3_w=inv4"},
75*4882a593Smuzhiyun 			{4, "R3_w=inv8"},
76*4882a593Smuzhiyun 			{5, "R3_w=inv16"},
77*4882a593Smuzhiyun 			{6, "R3_w=inv1"},
78*4882a593Smuzhiyun 			{7, "R4_w=inv32"},
79*4882a593Smuzhiyun 			{8, "R4_w=inv16"},
80*4882a593Smuzhiyun 			{9, "R4_w=inv8"},
81*4882a593Smuzhiyun 			{10, "R4_w=inv4"},
82*4882a593Smuzhiyun 			{11, "R4_w=inv2"},
83*4882a593Smuzhiyun 		},
84*4882a593Smuzhiyun 	},
85*4882a593Smuzhiyun 	{
86*4882a593Smuzhiyun 		.descr = "addsub",
87*4882a593Smuzhiyun 		.insns = {
88*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_3, 4),
89*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 4),
90*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 2),
91*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_4, 8),
92*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
93*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 2),
94*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_0, 0),
95*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
96*4882a593Smuzhiyun 		},
97*4882a593Smuzhiyun 		.prog_type = BPF_PROG_TYPE_SCHED_CLS,
98*4882a593Smuzhiyun 		.matches = {
99*4882a593Smuzhiyun 			{1, "R1=ctx(id=0,off=0,imm=0)"},
100*4882a593Smuzhiyun 			{1, "R10=fp0"},
101*4882a593Smuzhiyun 			{1, "R3_w=inv4"},
102*4882a593Smuzhiyun 			{2, "R3_w=inv8"},
103*4882a593Smuzhiyun 			{3, "R3_w=inv10"},
104*4882a593Smuzhiyun 			{4, "R4_w=inv8"},
105*4882a593Smuzhiyun 			{5, "R4_w=inv12"},
106*4882a593Smuzhiyun 			{6, "R4_w=inv14"},
107*4882a593Smuzhiyun 		},
108*4882a593Smuzhiyun 	},
109*4882a593Smuzhiyun 	{
110*4882a593Smuzhiyun 		.descr = "mul",
111*4882a593Smuzhiyun 		.insns = {
112*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_3, 7),
113*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 1),
114*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 2),
115*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 4),
116*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_0, 0),
117*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
118*4882a593Smuzhiyun 		},
119*4882a593Smuzhiyun 		.prog_type = BPF_PROG_TYPE_SCHED_CLS,
120*4882a593Smuzhiyun 		.matches = {
121*4882a593Smuzhiyun 			{1, "R1=ctx(id=0,off=0,imm=0)"},
122*4882a593Smuzhiyun 			{1, "R10=fp0"},
123*4882a593Smuzhiyun 			{1, "R3_w=inv7"},
124*4882a593Smuzhiyun 			{2, "R3_w=inv7"},
125*4882a593Smuzhiyun 			{3, "R3_w=inv14"},
126*4882a593Smuzhiyun 			{4, "R3_w=inv56"},
127*4882a593Smuzhiyun 		},
128*4882a593Smuzhiyun 	},
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	/* Tests using unknown values */
131*4882a593Smuzhiyun #define PREP_PKT_POINTERS \
132*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, \
133*4882a593Smuzhiyun 		    offsetof(struct __sk_buff, data)), \
134*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, \
135*4882a593Smuzhiyun 		    offsetof(struct __sk_buff, data_end))
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun #define LOAD_UNKNOWN(DST_REG) \
138*4882a593Smuzhiyun 	PREP_PKT_POINTERS, \
139*4882a593Smuzhiyun 	BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), \
140*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), \
141*4882a593Smuzhiyun 	BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_0, 1), \
142*4882a593Smuzhiyun 	BPF_EXIT_INSN(), \
143*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_B, DST_REG, BPF_REG_2, 0)
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	{
146*4882a593Smuzhiyun 		.descr = "unknown shift",
147*4882a593Smuzhiyun 		.insns = {
148*4882a593Smuzhiyun 			LOAD_UNKNOWN(BPF_REG_3),
149*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
150*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
151*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
152*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
153*4882a593Smuzhiyun 			LOAD_UNKNOWN(BPF_REG_4),
154*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_4, 5),
155*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
156*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
157*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
158*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
159*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_0, 0),
160*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
161*4882a593Smuzhiyun 		},
162*4882a593Smuzhiyun 		.prog_type = BPF_PROG_TYPE_SCHED_CLS,
163*4882a593Smuzhiyun 		.matches = {
164*4882a593Smuzhiyun 			{7, "R0_w=pkt(id=0,off=8,r=8,imm=0)"},
165*4882a593Smuzhiyun 			{7, "R3_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
166*4882a593Smuzhiyun 			{8, "R3_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"},
167*4882a593Smuzhiyun 			{9, "R3_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
168*4882a593Smuzhiyun 			{10, "R3_w=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"},
169*4882a593Smuzhiyun 			{11, "R3_w=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"},
170*4882a593Smuzhiyun 			{18, "R3=pkt_end(id=0,off=0,imm=0)"},
171*4882a593Smuzhiyun 			{18, "R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
172*4882a593Smuzhiyun 			{19, "R4_w=inv(id=0,umax_value=8160,var_off=(0x0; 0x1fe0))"},
173*4882a593Smuzhiyun 			{20, "R4_w=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"},
174*4882a593Smuzhiyun 			{21, "R4_w=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"},
175*4882a593Smuzhiyun 			{22, "R4_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
176*4882a593Smuzhiyun 			{23, "R4_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"},
177*4882a593Smuzhiyun 		},
178*4882a593Smuzhiyun 	},
179*4882a593Smuzhiyun 	{
180*4882a593Smuzhiyun 		.descr = "unknown mul",
181*4882a593Smuzhiyun 		.insns = {
182*4882a593Smuzhiyun 			LOAD_UNKNOWN(BPF_REG_3),
183*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
184*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 1),
185*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
186*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 2),
187*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
188*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 4),
189*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
190*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 8),
191*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 2),
192*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_0, 0),
193*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
194*4882a593Smuzhiyun 		},
195*4882a593Smuzhiyun 		.prog_type = BPF_PROG_TYPE_SCHED_CLS,
196*4882a593Smuzhiyun 		.matches = {
197*4882a593Smuzhiyun 			{7, "R3_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
198*4882a593Smuzhiyun 			{8, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
199*4882a593Smuzhiyun 			{9, "R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
200*4882a593Smuzhiyun 			{10, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
201*4882a593Smuzhiyun 			{11, "R4_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe))"},
202*4882a593Smuzhiyun 			{12, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
203*4882a593Smuzhiyun 			{13, "R4_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
204*4882a593Smuzhiyun 			{14, "R4_w=inv(id=1,umax_value=255,var_off=(0x0; 0xff))"},
205*4882a593Smuzhiyun 			{15, "R4_w=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8))"},
206*4882a593Smuzhiyun 			{16, "R4_w=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0))"},
207*4882a593Smuzhiyun 		},
208*4882a593Smuzhiyun 	},
209*4882a593Smuzhiyun 	{
210*4882a593Smuzhiyun 		.descr = "packet const offset",
211*4882a593Smuzhiyun 		.insns = {
212*4882a593Smuzhiyun 			PREP_PKT_POINTERS,
213*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_0, 0),
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 			/* Skip over ethernet header.  */
218*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
219*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
220*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
221*4882a593Smuzhiyun 			BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
222*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 0),
225*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 1),
226*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 2),
227*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 3),
228*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_5, 0),
229*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_5, 2),
230*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_0, 0),
233*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
234*4882a593Smuzhiyun 		},
235*4882a593Smuzhiyun 		.prog_type = BPF_PROG_TYPE_SCHED_CLS,
236*4882a593Smuzhiyun 		.matches = {
237*4882a593Smuzhiyun 			{4, "R5_w=pkt(id=0,off=0,r=0,imm=0)"},
238*4882a593Smuzhiyun 			{5, "R5_w=pkt(id=0,off=14,r=0,imm=0)"},
239*4882a593Smuzhiyun 			{6, "R4_w=pkt(id=0,off=14,r=0,imm=0)"},
240*4882a593Smuzhiyun 			{10, "R2=pkt(id=0,off=0,r=18,imm=0)"},
241*4882a593Smuzhiyun 			{10, "R5=pkt(id=0,off=14,r=18,imm=0)"},
242*4882a593Smuzhiyun 			{10, "R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff))"},
243*4882a593Smuzhiyun 			{14, "R4_w=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff))"},
244*4882a593Smuzhiyun 			{15, "R4_w=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff))"},
245*4882a593Smuzhiyun 		},
246*4882a593Smuzhiyun 	},
247*4882a593Smuzhiyun 	{
248*4882a593Smuzhiyun 		.descr = "packet variable offset",
249*4882a593Smuzhiyun 		.insns = {
250*4882a593Smuzhiyun 			LOAD_UNKNOWN(BPF_REG_6),
251*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2),
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 			/* First, add a constant to the R5 packet pointer,
254*4882a593Smuzhiyun 			 * then a variable with a known alignment.
255*4882a593Smuzhiyun 			 */
256*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
257*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
258*4882a593Smuzhiyun 			BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
259*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
260*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
261*4882a593Smuzhiyun 			BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
262*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
263*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 			/* Now, test in the other direction.  Adding first
266*4882a593Smuzhiyun 			 * the variable offset to R5, then the constant.
267*4882a593Smuzhiyun 			 */
268*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
269*4882a593Smuzhiyun 			BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
270*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
271*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
272*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
273*4882a593Smuzhiyun 			BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
274*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
275*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 			/* Test multiple accumulations of unknown values
278*4882a593Smuzhiyun 			 * into a packet pointer.
279*4882a593Smuzhiyun 			 */
280*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
281*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
282*4882a593Smuzhiyun 			BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
283*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 4),
284*4882a593Smuzhiyun 			BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
285*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
286*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
287*4882a593Smuzhiyun 			BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
288*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
289*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_0, 0),
292*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
293*4882a593Smuzhiyun 		},
294*4882a593Smuzhiyun 		.prog_type = BPF_PROG_TYPE_SCHED_CLS,
295*4882a593Smuzhiyun 		.matches = {
296*4882a593Smuzhiyun 			/* Calculated offset in R6 has unknown value, but known
297*4882a593Smuzhiyun 			 * alignment of 4.
298*4882a593Smuzhiyun 			 */
299*4882a593Smuzhiyun 			{8, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
300*4882a593Smuzhiyun 			{8, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
301*4882a593Smuzhiyun 			/* Offset is added to packet pointer R5, resulting in
302*4882a593Smuzhiyun 			 * known fixed offset, and variable offset from R6.
303*4882a593Smuzhiyun 			 */
304*4882a593Smuzhiyun 			{11, "R5_w=pkt(id=1,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
305*4882a593Smuzhiyun 			/* At the time the word size load is performed from R5,
306*4882a593Smuzhiyun 			 * it's total offset is NET_IP_ALIGN + reg->off (0) +
307*4882a593Smuzhiyun 			 * reg->aux_off (14) which is 16.  Then the variable
308*4882a593Smuzhiyun 			 * offset is considered using reg->aux_off_align which
309*4882a593Smuzhiyun 			 * is 4 and meets the load's requirements.
310*4882a593Smuzhiyun 			 */
311*4882a593Smuzhiyun 			{15, "R4=pkt(id=1,off=18,r=18,umax_value=1020,var_off=(0x0; 0x3fc))"},
312*4882a593Smuzhiyun 			{15, "R5=pkt(id=1,off=14,r=18,umax_value=1020,var_off=(0x0; 0x3fc))"},
313*4882a593Smuzhiyun 			/* Variable offset is added to R5 packet pointer,
314*4882a593Smuzhiyun 			 * resulting in auxiliary alignment of 4.
315*4882a593Smuzhiyun 			 */
316*4882a593Smuzhiyun 			{18, "R5_w=pkt(id=2,off=0,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
317*4882a593Smuzhiyun 			/* Constant offset is added to R5, resulting in
318*4882a593Smuzhiyun 			 * reg->off of 14.
319*4882a593Smuzhiyun 			 */
320*4882a593Smuzhiyun 			{19, "R5_w=pkt(id=2,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
321*4882a593Smuzhiyun 			/* At the time the word size load is performed from R5,
322*4882a593Smuzhiyun 			 * its total fixed offset is NET_IP_ALIGN + reg->off
323*4882a593Smuzhiyun 			 * (14) which is 16.  Then the variable offset is 4-byte
324*4882a593Smuzhiyun 			 * aligned, so the total offset is 4-byte aligned and
325*4882a593Smuzhiyun 			 * meets the load's requirements.
326*4882a593Smuzhiyun 			 */
327*4882a593Smuzhiyun 			{23, "R4=pkt(id=2,off=18,r=18,umax_value=1020,var_off=(0x0; 0x3fc))"},
328*4882a593Smuzhiyun 			{23, "R5=pkt(id=2,off=14,r=18,umax_value=1020,var_off=(0x0; 0x3fc))"},
329*4882a593Smuzhiyun 			/* Constant offset is added to R5 packet pointer,
330*4882a593Smuzhiyun 			 * resulting in reg->off value of 14.
331*4882a593Smuzhiyun 			 */
332*4882a593Smuzhiyun 			{26, "R5_w=pkt(id=0,off=14,r=8"},
333*4882a593Smuzhiyun 			/* Variable offset is added to R5, resulting in a
334*4882a593Smuzhiyun 			 * variable offset of (4n).
335*4882a593Smuzhiyun 			 */
336*4882a593Smuzhiyun 			{27, "R5_w=pkt(id=3,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
337*4882a593Smuzhiyun 			/* Constant is added to R5 again, setting reg->off to 18. */
338*4882a593Smuzhiyun 			{28, "R5_w=pkt(id=3,off=18,r=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
339*4882a593Smuzhiyun 			/* And once more we add a variable; resulting var_off
340*4882a593Smuzhiyun 			 * is still (4n), fixed offset is not changed.
341*4882a593Smuzhiyun 			 * Also, we create a new reg->id.
342*4882a593Smuzhiyun 			 */
343*4882a593Smuzhiyun 			{29, "R5_w=pkt(id=4,off=18,r=0,umax_value=2040,var_off=(0x0; 0x7fc)"},
344*4882a593Smuzhiyun 			/* At the time the word size load is performed from R5,
345*4882a593Smuzhiyun 			 * its total fixed offset is NET_IP_ALIGN + reg->off (18)
346*4882a593Smuzhiyun 			 * which is 20.  Then the variable offset is (4n), so
347*4882a593Smuzhiyun 			 * the total offset is 4-byte aligned and meets the
348*4882a593Smuzhiyun 			 * load's requirements.
349*4882a593Smuzhiyun 			 */
350*4882a593Smuzhiyun 			{33, "R4=pkt(id=4,off=22,r=22,umax_value=2040,var_off=(0x0; 0x7fc)"},
351*4882a593Smuzhiyun 			{33, "R5=pkt(id=4,off=18,r=22,umax_value=2040,var_off=(0x0; 0x7fc)"},
352*4882a593Smuzhiyun 		},
353*4882a593Smuzhiyun 	},
354*4882a593Smuzhiyun 	{
355*4882a593Smuzhiyun 		.descr = "packet variable offset 2",
356*4882a593Smuzhiyun 		.insns = {
357*4882a593Smuzhiyun 			/* Create an unknown offset, (4n+2)-aligned */
358*4882a593Smuzhiyun 			LOAD_UNKNOWN(BPF_REG_6),
359*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2),
360*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 14),
361*4882a593Smuzhiyun 			/* Add it to the packet pointer */
362*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
363*4882a593Smuzhiyun 			BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
364*4882a593Smuzhiyun 			/* Check bounds and perform a read */
365*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
366*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
367*4882a593Smuzhiyun 			BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
368*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
369*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_5, 0),
370*4882a593Smuzhiyun 			/* Make a (4n) offset from the value we just read */
371*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_AND, BPF_REG_6, 0xff),
372*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2),
373*4882a593Smuzhiyun 			/* Add it to the packet pointer */
374*4882a593Smuzhiyun 			BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
375*4882a593Smuzhiyun 			/* Check bounds and perform a read */
376*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
377*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
378*4882a593Smuzhiyun 			BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
379*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
380*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_5, 0),
381*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_0, 0),
382*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
383*4882a593Smuzhiyun 		},
384*4882a593Smuzhiyun 		.prog_type = BPF_PROG_TYPE_SCHED_CLS,
385*4882a593Smuzhiyun 		.matches = {
386*4882a593Smuzhiyun 			/* Calculated offset in R6 has unknown value, but known
387*4882a593Smuzhiyun 			 * alignment of 4.
388*4882a593Smuzhiyun 			 */
389*4882a593Smuzhiyun 			{8, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
390*4882a593Smuzhiyun 			{8, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
391*4882a593Smuzhiyun 			/* Adding 14 makes R6 be (4n+2) */
392*4882a593Smuzhiyun 			{9, "R6_w=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"},
393*4882a593Smuzhiyun 			/* Packet pointer has (4n+2) offset */
394*4882a593Smuzhiyun 			{11, "R5_w=pkt(id=1,off=0,r=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)"},
395*4882a593Smuzhiyun 			{13, "R4=pkt(id=1,off=4,r=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)"},
396*4882a593Smuzhiyun 			/* At the time the word size load is performed from R5,
397*4882a593Smuzhiyun 			 * its total fixed offset is NET_IP_ALIGN + reg->off (0)
398*4882a593Smuzhiyun 			 * which is 2.  Then the variable offset is (4n+2), so
399*4882a593Smuzhiyun 			 * the total offset is 4-byte aligned and meets the
400*4882a593Smuzhiyun 			 * load's requirements.
401*4882a593Smuzhiyun 			 */
402*4882a593Smuzhiyun 			{15, "R5=pkt(id=1,off=0,r=4,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)"},
403*4882a593Smuzhiyun 			/* Newly read value in R6 was shifted left by 2, so has
404*4882a593Smuzhiyun 			 * known alignment of 4.
405*4882a593Smuzhiyun 			 */
406*4882a593Smuzhiyun 			{18, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
407*4882a593Smuzhiyun 			/* Added (4n) to packet pointer's (4n+2) var_off, giving
408*4882a593Smuzhiyun 			 * another (4n+2).
409*4882a593Smuzhiyun 			 */
410*4882a593Smuzhiyun 			{19, "R5_w=pkt(id=2,off=0,r=0,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc)"},
411*4882a593Smuzhiyun 			{21, "R4=pkt(id=2,off=4,r=0,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc)"},
412*4882a593Smuzhiyun 			/* At the time the word size load is performed from R5,
413*4882a593Smuzhiyun 			 * its total fixed offset is NET_IP_ALIGN + reg->off (0)
414*4882a593Smuzhiyun 			 * which is 2.  Then the variable offset is (4n+2), so
415*4882a593Smuzhiyun 			 * the total offset is 4-byte aligned and meets the
416*4882a593Smuzhiyun 			 * load's requirements.
417*4882a593Smuzhiyun 			 */
418*4882a593Smuzhiyun 			{23, "R5=pkt(id=2,off=0,r=4,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc)"},
419*4882a593Smuzhiyun 		},
420*4882a593Smuzhiyun 	},
421*4882a593Smuzhiyun 	{
422*4882a593Smuzhiyun 		.descr = "dubious pointer arithmetic",
423*4882a593Smuzhiyun 		.insns = {
424*4882a593Smuzhiyun 			PREP_PKT_POINTERS,
425*4882a593Smuzhiyun 			BPF_MOV64_IMM(BPF_REG_0, 0),
426*4882a593Smuzhiyun 			/* (ptr - ptr) << 2 */
427*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_5, BPF_REG_3),
428*4882a593Smuzhiyun 			BPF_ALU64_REG(BPF_SUB, BPF_REG_5, BPF_REG_2),
429*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_5, 2),
430*4882a593Smuzhiyun 			/* We have a (4n) value.  Let's make a packet offset
431*4882a593Smuzhiyun 			 * out of it.  First add 14, to make it a (4n+2)
432*4882a593Smuzhiyun 			 */
433*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
434*4882a593Smuzhiyun 			/* Then make sure it's nonnegative */
435*4882a593Smuzhiyun 			BPF_JMP_IMM(BPF_JSGE, BPF_REG_5, 0, 1),
436*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
437*4882a593Smuzhiyun 			/* Add it to packet pointer */
438*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_6, BPF_REG_2),
439*4882a593Smuzhiyun 			BPF_ALU64_REG(BPF_ADD, BPF_REG_6, BPF_REG_5),
440*4882a593Smuzhiyun 			/* Check bounds and perform a read */
441*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_4, BPF_REG_6),
442*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
443*4882a593Smuzhiyun 			BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
444*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
445*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_6, 0),
446*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
447*4882a593Smuzhiyun 		},
448*4882a593Smuzhiyun 		.prog_type = BPF_PROG_TYPE_SCHED_CLS,
449*4882a593Smuzhiyun 		.result = REJECT,
450*4882a593Smuzhiyun 		.matches = {
451*4882a593Smuzhiyun 			{4, "R5_w=pkt_end(id=0,off=0,imm=0)"},
452*4882a593Smuzhiyun 			/* (ptr - ptr) << 2 == unknown, (4n) */
453*4882a593Smuzhiyun 			{6, "R5_w=inv(id=0,smax_value=9223372036854775804,umax_value=18446744073709551612,var_off=(0x0; 0xfffffffffffffffc)"},
454*4882a593Smuzhiyun 			/* (4n) + 14 == (4n+2).  We blow our bounds, because
455*4882a593Smuzhiyun 			 * the add could overflow.
456*4882a593Smuzhiyun 			 */
457*4882a593Smuzhiyun 			{7, "R5_w=inv(id=0,smin_value=-9223372036854775806,smax_value=9223372036854775806,umin_value=2,umax_value=18446744073709551614,var_off=(0x2; 0xfffffffffffffffc)"},
458*4882a593Smuzhiyun 			/* Checked s>=0 */
459*4882a593Smuzhiyun 			{9, "R5=inv(id=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc)"},
460*4882a593Smuzhiyun 			/* packet pointer + nonnegative (4n+2) */
461*4882a593Smuzhiyun 			{11, "R6_w=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc)"},
462*4882a593Smuzhiyun 			{13, "R4_w=pkt(id=1,off=4,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc)"},
463*4882a593Smuzhiyun 			/* NET_IP_ALIGN + (4n+2) == (4n), alignment is fine.
464*4882a593Smuzhiyun 			 * We checked the bounds, but it might have been able
465*4882a593Smuzhiyun 			 * to overflow if the packet pointer started in the
466*4882a593Smuzhiyun 			 * upper half of the address space.
467*4882a593Smuzhiyun 			 * So we did not get a 'range' on R6, and the access
468*4882a593Smuzhiyun 			 * attempt will fail.
469*4882a593Smuzhiyun 			 */
470*4882a593Smuzhiyun 			{15, "R6_w=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc)"},
471*4882a593Smuzhiyun 		}
472*4882a593Smuzhiyun 	},
473*4882a593Smuzhiyun 	{
474*4882a593Smuzhiyun 		.descr = "variable subtraction",
475*4882a593Smuzhiyun 		.insns = {
476*4882a593Smuzhiyun 			/* Create an unknown offset, (4n+2)-aligned */
477*4882a593Smuzhiyun 			LOAD_UNKNOWN(BPF_REG_6),
478*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),
479*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2),
480*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 14),
481*4882a593Smuzhiyun 			/* Create another unknown, (4n)-aligned, and subtract
482*4882a593Smuzhiyun 			 * it from the first one
483*4882a593Smuzhiyun 			 */
484*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_7, 2),
485*4882a593Smuzhiyun 			BPF_ALU64_REG(BPF_SUB, BPF_REG_6, BPF_REG_7),
486*4882a593Smuzhiyun 			/* Bounds-check the result */
487*4882a593Smuzhiyun 			BPF_JMP_IMM(BPF_JSGE, BPF_REG_6, 0, 1),
488*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
489*4882a593Smuzhiyun 			/* Add it to the packet pointer */
490*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
491*4882a593Smuzhiyun 			BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
492*4882a593Smuzhiyun 			/* Check bounds and perform a read */
493*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
494*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
495*4882a593Smuzhiyun 			BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
496*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
497*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_5, 0),
498*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
499*4882a593Smuzhiyun 		},
500*4882a593Smuzhiyun 		.prog_type = BPF_PROG_TYPE_SCHED_CLS,
501*4882a593Smuzhiyun 		.matches = {
502*4882a593Smuzhiyun 			/* Calculated offset in R6 has unknown value, but known
503*4882a593Smuzhiyun 			 * alignment of 4.
504*4882a593Smuzhiyun 			 */
505*4882a593Smuzhiyun 			{7, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
506*4882a593Smuzhiyun 			{9, "R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
507*4882a593Smuzhiyun 			/* Adding 14 makes R6 be (4n+2) */
508*4882a593Smuzhiyun 			{10, "R6_w=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"},
509*4882a593Smuzhiyun 			/* New unknown value in R7 is (4n) */
510*4882a593Smuzhiyun 			{11, "R7_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},
511*4882a593Smuzhiyun 			/* Subtracting it from R6 blows our unsigned bounds */
512*4882a593Smuzhiyun 			{12, "R6=inv(id=0,smin_value=-1006,smax_value=1034,umin_value=2,umax_value=18446744073709551614,var_off=(0x2; 0xfffffffffffffffc)"},
513*4882a593Smuzhiyun 			/* Checked s>= 0 */
514*4882a593Smuzhiyun 			{14, "R6=inv(id=0,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc))"},
515*4882a593Smuzhiyun 			/* At the time the word size load is performed from R5,
516*4882a593Smuzhiyun 			 * its total fixed offset is NET_IP_ALIGN + reg->off (0)
517*4882a593Smuzhiyun 			 * which is 2.  Then the variable offset is (4n+2), so
518*4882a593Smuzhiyun 			 * the total offset is 4-byte aligned and meets the
519*4882a593Smuzhiyun 			 * load's requirements.
520*4882a593Smuzhiyun 			 */
521*4882a593Smuzhiyun 			{20, "R5=pkt(id=2,off=0,r=4,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc)"},
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 		},
524*4882a593Smuzhiyun 	},
525*4882a593Smuzhiyun 	{
526*4882a593Smuzhiyun 		.descr = "pointer variable subtraction",
527*4882a593Smuzhiyun 		.insns = {
528*4882a593Smuzhiyun 			/* Create an unknown offset, (4n+2)-aligned and bounded
529*4882a593Smuzhiyun 			 * to [14,74]
530*4882a593Smuzhiyun 			 */
531*4882a593Smuzhiyun 			LOAD_UNKNOWN(BPF_REG_6),
532*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_7, BPF_REG_6),
533*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_AND, BPF_REG_6, 0xf),
534*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2),
535*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 14),
536*4882a593Smuzhiyun 			/* Subtract it from the packet pointer */
537*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
538*4882a593Smuzhiyun 			BPF_ALU64_REG(BPF_SUB, BPF_REG_5, BPF_REG_6),
539*4882a593Smuzhiyun 			/* Create another unknown, (4n)-aligned and >= 74.
540*4882a593Smuzhiyun 			 * That in fact means >= 76, since 74 % 4 == 2
541*4882a593Smuzhiyun 			 */
542*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_LSH, BPF_REG_7, 2),
543*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 76),
544*4882a593Smuzhiyun 			/* Add it to the packet pointer */
545*4882a593Smuzhiyun 			BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_7),
546*4882a593Smuzhiyun 			/* Check bounds and perform a read */
547*4882a593Smuzhiyun 			BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
548*4882a593Smuzhiyun 			BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
549*4882a593Smuzhiyun 			BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
550*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
551*4882a593Smuzhiyun 			BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_5, 0),
552*4882a593Smuzhiyun 			BPF_EXIT_INSN(),
553*4882a593Smuzhiyun 		},
554*4882a593Smuzhiyun 		.prog_type = BPF_PROG_TYPE_SCHED_CLS,
555*4882a593Smuzhiyun 		.matches = {
556*4882a593Smuzhiyun 			/* Calculated offset in R6 has unknown value, but known
557*4882a593Smuzhiyun 			 * alignment of 4.
558*4882a593Smuzhiyun 			 */
559*4882a593Smuzhiyun 			{7, "R2_w=pkt(id=0,off=0,r=8,imm=0)"},
560*4882a593Smuzhiyun 			{10, "R6_w=inv(id=0,umax_value=60,var_off=(0x0; 0x3c))"},
561*4882a593Smuzhiyun 			/* Adding 14 makes R6 be (4n+2) */
562*4882a593Smuzhiyun 			{11, "R6_w=inv(id=0,umin_value=14,umax_value=74,var_off=(0x2; 0x7c))"},
563*4882a593Smuzhiyun 			/* Subtracting from packet pointer overflows ubounds */
564*4882a593Smuzhiyun 			{13, "R5_w=pkt(id=2,off=0,r=8,umin_value=18446744073709551542,umax_value=18446744073709551602,var_off=(0xffffffffffffff82; 0x7c)"},
565*4882a593Smuzhiyun 			/* New unknown value in R7 is (4n), >= 76 */
566*4882a593Smuzhiyun 			{15, "R7_w=inv(id=0,umin_value=76,umax_value=1096,var_off=(0x0; 0x7fc))"},
567*4882a593Smuzhiyun 			/* Adding it to packet pointer gives nice bounds again */
568*4882a593Smuzhiyun 			{16, "R5_w=pkt(id=3,off=0,r=0,umin_value=2,umax_value=1082,var_off=(0x2; 0xfffffffc)"},
569*4882a593Smuzhiyun 			/* At the time the word size load is performed from R5,
570*4882a593Smuzhiyun 			 * its total fixed offset is NET_IP_ALIGN + reg->off (0)
571*4882a593Smuzhiyun 			 * which is 2.  Then the variable offset is (4n+2), so
572*4882a593Smuzhiyun 			 * the total offset is 4-byte aligned and meets the
573*4882a593Smuzhiyun 			 * load's requirements.
574*4882a593Smuzhiyun 			 */
575*4882a593Smuzhiyun 			{20, "R5=pkt(id=3,off=0,r=4,umin_value=2,umax_value=1082,var_off=(0x2; 0xfffffffc)"},
576*4882a593Smuzhiyun 		},
577*4882a593Smuzhiyun 	},
578*4882a593Smuzhiyun };
579*4882a593Smuzhiyun 
probe_filter_length(const struct bpf_insn * fp)580*4882a593Smuzhiyun static int probe_filter_length(const struct bpf_insn *fp)
581*4882a593Smuzhiyun {
582*4882a593Smuzhiyun 	int len;
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	for (len = MAX_INSNS - 1; len > 0; --len)
585*4882a593Smuzhiyun 		if (fp[len].code != 0 || fp[len].imm != 0)
586*4882a593Smuzhiyun 			break;
587*4882a593Smuzhiyun 	return len + 1;
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun static char bpf_vlog[32768];
591*4882a593Smuzhiyun 
do_test_single(struct bpf_align_test * test)592*4882a593Smuzhiyun static int do_test_single(struct bpf_align_test *test)
593*4882a593Smuzhiyun {
594*4882a593Smuzhiyun 	struct bpf_insn *prog = test->insns;
595*4882a593Smuzhiyun 	int prog_type = test->prog_type;
596*4882a593Smuzhiyun 	char bpf_vlog_copy[32768];
597*4882a593Smuzhiyun 	const char *line_ptr;
598*4882a593Smuzhiyun 	int cur_line = -1;
599*4882a593Smuzhiyun 	int prog_len, i;
600*4882a593Smuzhiyun 	int fd_prog;
601*4882a593Smuzhiyun 	int ret;
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	prog_len = probe_filter_length(prog);
604*4882a593Smuzhiyun 	fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
605*4882a593Smuzhiyun 				     prog, prog_len, BPF_F_STRICT_ALIGNMENT,
606*4882a593Smuzhiyun 				     "GPL", 0, bpf_vlog, sizeof(bpf_vlog), 2);
607*4882a593Smuzhiyun 	if (fd_prog < 0 && test->result != REJECT) {
608*4882a593Smuzhiyun 		printf("Failed to load program.\n");
609*4882a593Smuzhiyun 		printf("%s", bpf_vlog);
610*4882a593Smuzhiyun 		ret = 1;
611*4882a593Smuzhiyun 	} else if (fd_prog >= 0 && test->result == REJECT) {
612*4882a593Smuzhiyun 		printf("Unexpected success to load!\n");
613*4882a593Smuzhiyun 		printf("%s", bpf_vlog);
614*4882a593Smuzhiyun 		ret = 1;
615*4882a593Smuzhiyun 		close(fd_prog);
616*4882a593Smuzhiyun 	} else {
617*4882a593Smuzhiyun 		ret = 0;
618*4882a593Smuzhiyun 		/* We make a local copy so that we can strtok() it */
619*4882a593Smuzhiyun 		strncpy(bpf_vlog_copy, bpf_vlog, sizeof(bpf_vlog_copy));
620*4882a593Smuzhiyun 		line_ptr = strtok(bpf_vlog_copy, "\n");
621*4882a593Smuzhiyun 		for (i = 0; i < MAX_MATCHES; i++) {
622*4882a593Smuzhiyun 			struct bpf_reg_match m = test->matches[i];
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 			if (!m.match)
625*4882a593Smuzhiyun 				break;
626*4882a593Smuzhiyun 			while (line_ptr) {
627*4882a593Smuzhiyun 				cur_line = -1;
628*4882a593Smuzhiyun 				sscanf(line_ptr, "%u: ", &cur_line);
629*4882a593Smuzhiyun 				if (cur_line == m.line)
630*4882a593Smuzhiyun 					break;
631*4882a593Smuzhiyun 				line_ptr = strtok(NULL, "\n");
632*4882a593Smuzhiyun 			}
633*4882a593Smuzhiyun 			if (!line_ptr) {
634*4882a593Smuzhiyun 				printf("Failed to find line %u for match: %s\n",
635*4882a593Smuzhiyun 				       m.line, m.match);
636*4882a593Smuzhiyun 				ret = 1;
637*4882a593Smuzhiyun 				printf("%s", bpf_vlog);
638*4882a593Smuzhiyun 				break;
639*4882a593Smuzhiyun 			}
640*4882a593Smuzhiyun 			if (!strstr(line_ptr, m.match)) {
641*4882a593Smuzhiyun 				printf("Failed to find match %u: %s\n",
642*4882a593Smuzhiyun 				       m.line, m.match);
643*4882a593Smuzhiyun 				ret = 1;
644*4882a593Smuzhiyun 				printf("%s", bpf_vlog);
645*4882a593Smuzhiyun 				break;
646*4882a593Smuzhiyun 			}
647*4882a593Smuzhiyun 		}
648*4882a593Smuzhiyun 		if (fd_prog >= 0)
649*4882a593Smuzhiyun 			close(fd_prog);
650*4882a593Smuzhiyun 	}
651*4882a593Smuzhiyun 	return ret;
652*4882a593Smuzhiyun }
653*4882a593Smuzhiyun 
test_align(void)654*4882a593Smuzhiyun void test_align(void)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun 	unsigned int i;
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
659*4882a593Smuzhiyun 		struct bpf_align_test *test = &tests[i];
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 		if (!test__start_subtest(test->descr))
662*4882a593Smuzhiyun 			continue;
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 		CHECK_FAIL(do_test_single(test));
665*4882a593Smuzhiyun 	}
666*4882a593Smuzhiyun }
667