]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/testing/selftests/bpf/test_align.c
bpf: Handle multiple variable additions into packet pointers in verifier.
[karo-tx-linux.git] / tools / testing / selftests / bpf / test_align.c
1 #include <asm/types.h>
2 #include <linux/types.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <errno.h>
8 #include <string.h>
9 #include <stddef.h>
10 #include <stdbool.h>
11
12 #include <linux/unistd.h>
13 #include <linux/filter.h>
14 #include <linux/bpf_perf_event.h>
15 #include <linux/bpf.h>
16
17 #include <bpf/bpf.h>
18
19 #include "../../../include/linux/filter.h"
20
21 #ifndef ARRAY_SIZE
22 # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
23 #endif
24
25 #define MAX_INSNS       512
26 #define MAX_MATCHES     16
27
28 struct bpf_align_test {
29         const char *descr;
30         struct bpf_insn insns[MAX_INSNS];
31         enum {
32                 UNDEF,
33                 ACCEPT,
34                 REJECT
35         } result;
36         enum bpf_prog_type prog_type;
37         const char *matches[MAX_MATCHES];
38 };
39
40 static struct bpf_align_test tests[] = {
41         {
42                 .descr = "mov",
43                 .insns = {
44                         BPF_MOV64_IMM(BPF_REG_3, 2),
45                         BPF_MOV64_IMM(BPF_REG_3, 4),
46                         BPF_MOV64_IMM(BPF_REG_3, 8),
47                         BPF_MOV64_IMM(BPF_REG_3, 16),
48                         BPF_MOV64_IMM(BPF_REG_3, 32),
49                         BPF_MOV64_IMM(BPF_REG_0, 0),
50                         BPF_EXIT_INSN(),
51                 },
52                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
53                 .matches = {
54                         "1: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
55                         "2: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
56                         "3: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
57                         "4: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
58                         "5: R1=ctx R3=imm32,min_value=32,max_value=32,min_align=32 R10=fp",
59                 },
60         },
61         {
62                 .descr = "shift",
63                 .insns = {
64                         BPF_MOV64_IMM(BPF_REG_3, 1),
65                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
66                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
67                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
68                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
69                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_3, 4),
70                         BPF_MOV64_IMM(BPF_REG_4, 32),
71                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
72                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
73                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
74                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
75                         BPF_MOV64_IMM(BPF_REG_0, 0),
76                         BPF_EXIT_INSN(),
77                 },
78                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
79                 .matches = {
80                         "1: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp",
81                         "2: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
82                         "3: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
83                         "4: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
84                         "5: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
85                         "6: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp",
86                         "7: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm32,min_value=32,max_value=32,min_align=32 R10=fp",
87                         "8: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
88                         "9: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
89                         "10: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
90                         "11: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
91                 },
92         },
93         {
94                 .descr = "addsub",
95                 .insns = {
96                         BPF_MOV64_IMM(BPF_REG_3, 4),
97                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 4),
98                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 2),
99                         BPF_MOV64_IMM(BPF_REG_4, 8),
100                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
101                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 2),
102                         BPF_MOV64_IMM(BPF_REG_0, 0),
103                         BPF_EXIT_INSN(),
104                 },
105                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
106                 .matches = {
107                         "1: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
108                         "2: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=4 R10=fp",
109                         "3: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R10=fp",
110                         "4: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
111                         "5: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm12,min_value=12,max_value=12,min_align=4 R10=fp",
112                         "6: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm14,min_value=14,max_value=14,min_align=2 R10=fp",
113                 },
114         },
115         {
116                 .descr = "mul",
117                 .insns = {
118                         BPF_MOV64_IMM(BPF_REG_3, 7),
119                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 1),
120                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 2),
121                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 4),
122                         BPF_MOV64_IMM(BPF_REG_0, 0),
123                         BPF_EXIT_INSN(),
124                 },
125                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
126                 .matches = {
127                         "1: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp",
128                         "2: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp",
129                         "3: R1=ctx R3=imm14,min_value=14,max_value=14,min_align=2 R10=fp",
130                         "4: R1=ctx R3=imm56,min_value=56,max_value=56,min_align=4 R10=fp",
131                 },
132         },
133
134 #define PREP_PKT_POINTERS \
135         BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, \
136                     offsetof(struct __sk_buff, data)), \
137         BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, \
138                     offsetof(struct __sk_buff, data_end))
139
140 #define LOAD_UNKNOWN(DST_REG) \
141         PREP_PKT_POINTERS, \
142         BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), \
143         BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), \
144         BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_0, 1), \
145         BPF_EXIT_INSN(), \
146         BPF_LDX_MEM(BPF_B, DST_REG, BPF_REG_2, 0)
147
148         {
149                 .descr = "unknown shift",
150                 .insns = {
151                         LOAD_UNKNOWN(BPF_REG_3),
152                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
153                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
154                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
155                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
156                         LOAD_UNKNOWN(BPF_REG_4),
157                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_4, 5),
158                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
159                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
160                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
161                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
162                         BPF_MOV64_IMM(BPF_REG_0, 0),
163                         BPF_EXIT_INSN(),
164                 },
165                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
166                 .matches = {
167                         "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp",
168                         "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv55,min_align=2 R10=fp",
169                         "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv54,min_align=4 R10=fp",
170                         "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv53,min_align=8 R10=fp",
171                         "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv52,min_align=16 R10=fp",
172                         "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv56 R10=fp",
173                         "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv51,min_align=32 R10=fp",
174                         "20: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv52,min_align=16 R10=fp",
175                         "21: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv53,min_align=8 R10=fp",
176                         "22: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv54,min_align=4 R10=fp",
177                         "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv55,min_align=2 R10=fp",
178                 },
179         },
180         {
181                 .descr = "unknown mul",
182                 .insns = {
183                         LOAD_UNKNOWN(BPF_REG_3),
184                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
185                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 1),
186                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
187                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 2),
188                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
189                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 4),
190                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
191                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 8),
192                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 2),
193                         BPF_MOV64_IMM(BPF_REG_0, 0),
194                         BPF_EXIT_INSN(),
195                 },
196                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
197                 .matches = {
198                         "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp",
199                         "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
200                         "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv55,min_align=1 R10=fp",
201                         "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
202                         "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv54,min_align=2 R10=fp",
203                         "12: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
204                         "13: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv53,min_align=4 R10=fp",
205                         "14: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
206                         "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv52,min_align=8 R10=fp",
207                         "16: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv50,min_align=8 R10=fp"
208                 },
209         },
210         {
211                 .descr = "packet const offset",
212                 .insns = {
213                         PREP_PKT_POINTERS,
214                         BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
215
216                         BPF_MOV64_IMM(BPF_REG_0, 0),
217
218                         /* Skip over ethernet header.  */
219                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
220                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
221                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
222                         BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
223                         BPF_EXIT_INSN(),
224
225                         BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 0),
226                         BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 1),
227                         BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 2),
228                         BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 3),
229                         BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_5, 0),
230                         BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_5, 2),
231                         BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
232
233                         BPF_MOV64_IMM(BPF_REG_0, 0),
234                         BPF_EXIT_INSN(),
235                 },
236                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
237                 .matches = {
238                         "4: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=0,r=0) R10=fp",
239                         "5: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=14,r=0) R10=fp",
240                         "6: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R4=pkt(id=0,off=14,r=0) R5=pkt(id=0,off=14,r=0) R10=fp",
241                         "10: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv56 R5=pkt(id=0,off=14,r=18) R10=fp",
242                         "14: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp",
243                         "15: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp",
244                 },
245         },
246         {
247                 .descr = "packet variable offset",
248                 .insns = {
249                         LOAD_UNKNOWN(BPF_REG_6),
250                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2),
251
252                         /* First, add a constant to the R5 packet pointer,
253                          * then a variable with a known alignment.
254                          */
255                         BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
256                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
257                         BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
258                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
259                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
260                         BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
261                         BPF_EXIT_INSN(),
262                         BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
263
264                         /* Now, test in the other direction.  Adding first
265                          * the variable offset to R5, then the constant.
266                          */
267                         BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
268                         BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
269                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
270                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
271                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
272                         BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
273                         BPF_EXIT_INSN(),
274                         BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
275
276                         /* Test multiple accumulations of unknown values
277                          * into a packet pointer.
278                          */
279                         BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
280                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
281                         BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
282                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 4),
283                         BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
284                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
285                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
286                         BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
287                         BPF_EXIT_INSN(),
288                         BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
289
290                         BPF_MOV64_IMM(BPF_REG_0, 0),
291                         BPF_EXIT_INSN(),
292                 },
293                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
294                 .matches = {
295                         /* Calculated offset in R6 has unknown value, but known
296                          * alignment of 4.
297                          */
298                         "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R6=inv54,min_align=4 R10=fp",
299
300                         /* Offset is added to packet pointer R5, resulting in known
301                          * auxiliary alignment and offset.
302                          */
303                         "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R5=pkt(id=1,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
304
305                         /* At the time the word size load is performed from R5,
306                          * it's total offset is NET_IP_ALIGN + reg->off (0) +
307                          * reg->aux_off (14) which is 16.  Then the variable
308                          * offset is considered using reg->aux_off_align which
309                          * is 4 and meets the load's requirements.
310                          */
311                         "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=1,off=4,r=4),aux_off=14,aux_off_align=4 R5=pkt(id=1,off=0,r=4),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
312
313
314                         /* Variable offset is added to R5 packet pointer,
315                          * resulting in auxiliary alignment of 4.
316                          */
317                         "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=0,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
318
319                         /* Constant offset is added to R5, resulting in
320                          * reg->off of 14.
321                          */
322                         "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=14,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
323
324                         /* At the time the word size load is performed from R5,
325                          * it's total offset is NET_IP_ALIGN + reg->off (14) which
326                          * is 16.  Then the variable offset is considered using
327                          * reg->aux_off_align which is 4 and meets the load's
328                          * requirements.
329                          */
330                         "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=2,off=18,r=18),aux_off_align=4 R5=pkt(id=2,off=14,r=18),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
331
332                         /* Constant offset is added to R5 packet pointer,
333                          * resulting in reg->off value of 14.
334                          */
335                         "26: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=0,off=14,r=8) R6=inv54,min_align=4 R10=fp",
336                         /* Variable offset is added to R5, resulting in an
337                          * auxiliary offset of 14, and an auxiliary alignment of 4.
338                          */
339                         "27: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
340                         /* Constant is added to R5 again, setting reg->off to 4. */
341                         "28: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=4,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
342                         /* And once more we add a variable, which causes an accumulation
343                          * of reg->off into reg->aux_off_align, with resulting value of
344                          * 18.  The auxiliary alignment stays at 4.
345                          */
346                         "29: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=4,off=0,r=0),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
347                         /* At the time the word size load is performed from R5,
348                          * it's total offset is NET_IP_ALIGN + reg->off (0) +
349                          * reg->aux_off (18) which is 20.  Then the variable offset
350                          * is considered using reg->aux_off_align which is 4 and meets
351                          * the load's requirements.
352                          */
353                         "33: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=4,off=4,r=4),aux_off=18,aux_off_align=4 R5=pkt(id=4,off=0,r=4),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
354                 },
355         },
356 };
357
358 static int probe_filter_length(const struct bpf_insn *fp)
359 {
360         int len;
361
362         for (len = MAX_INSNS - 1; len > 0; --len)
363                 if (fp[len].code != 0 || fp[len].imm != 0)
364                         break;
365         return len + 1;
366 }
367
368 static char bpf_vlog[32768];
369
370 static int do_test_single(struct bpf_align_test *test)
371 {
372         struct bpf_insn *prog = test->insns;
373         int prog_type = test->prog_type;
374         int prog_len, i;
375         int fd_prog;
376         int ret;
377
378         prog_len = probe_filter_length(prog);
379         fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
380                                      prog, prog_len, 1, "GPL", 0,
381                                      bpf_vlog, sizeof(bpf_vlog));
382         if (fd_prog < 0) {
383                 printf("Failed to load program.\n");
384                 printf("%s", bpf_vlog);
385                 ret = 1;
386         } else {
387                 ret = 0;
388                 for (i = 0; i < MAX_MATCHES; i++) {
389                         const char *t, *m = test->matches[i];
390
391                         if (!m)
392                                 break;
393                         t = strstr(bpf_vlog, m);
394                         if (!t) {
395                                 printf("Failed to find match: %s\n", m);
396                                 ret = 1;
397                                 printf("%s", bpf_vlog);
398                                 break;
399                         }
400                 }
401                 close(fd_prog);
402         }
403         return ret;
404 }
405
406 static int do_test(unsigned int from, unsigned int to)
407 {
408         int all_pass = 0;
409         int all_fail = 0;
410         unsigned int i;
411
412         for (i = from; i < to; i++) {
413                 struct bpf_align_test *test = &tests[i];
414                 int fail;
415
416                 printf("Test %3d: %s ... ",
417                        i, test->descr);
418                 fail = do_test_single(test);
419                 if (fail) {
420                         all_fail++;
421                         printf("FAIL\n");
422                 } else {
423                         all_pass++;
424                         printf("PASS\n");
425                 }
426         }
427         printf("Results: %d pass %d fail\n",
428                all_pass, all_fail);
429         return 0;
430 }
431
432 int main(int argc, char **argv)
433 {
434         unsigned int from = 0, to = ARRAY_SIZE(tests);
435
436         if (argc == 3) {
437                 unsigned int l = atoi(argv[argc - 2]);
438                 unsigned int u = atoi(argv[argc - 1]);
439
440                 if (l < to && u < to) {
441                         from = l;
442                         to   = u + 1;
443                 }
444         } else if (argc == 2) {
445                 unsigned int t = atoi(argv[argc - 1]);
446
447                 if (t < to) {
448                         from = t;
449                         to   = t + 1;
450                 }
451         }
452         return do_test(from, to);
453 }