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