1 /*        $NetBSD: t_cop.c,v 1.4 2014/07/13 21:35:33 alnsn Exp $ */
2 
3 /*-
4  * Copyright (c) 2013-2014 Alexander Nasonov.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: t_cop.c,v 1.4 2014/07/13 21:35:33 alnsn Exp $");
34 
35 #include <atf-c.h>
36 #include <stdint.h>
37 #include <string.h>
38 
39 #define __BPF_PRIVATE
40 #include <net/bpf.h>
41 #include <net/bpfjit.h>
42 
43 static uint32_t retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
44 static uint32_t retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
45 static uint32_t retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
46 static uint32_t retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
47 static uint32_t setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
48 
49 static const bpf_copfunc_t copfuncs[] = {
50           &retA,
51           &retBL,
52           &retWL,
53           &retNF,
54           &setARG
55 };
56 
57 static const bpf_ctx_t ctx = {
58           .copfuncs = copfuncs,
59           .nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
60           .extwords = 0
61 };
62 
63 static uint32_t
retA(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)64 retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
65 {
66 
67           return A;
68 }
69 
70 static uint32_t
retBL(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)71 retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
72 {
73 
74           return args->buflen;
75 }
76 
77 static uint32_t
retWL(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)78 retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
79 {
80 
81           return args->wirelen;
82 }
83 
84 static uint32_t
retNF(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)85 retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
86 {
87 
88           return bc->nfuncs;
89 }
90 
91 /*
92  * COP function with a side effect.
93  */
94 static uint32_t
setARG(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)95 setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
96 {
97           bool *arg = (bool *)args->arg;
98           bool old = *arg;
99 
100           *arg = true;
101           return old;
102 }
103 
104 ATF_TC(libbpfjit_cop_no_ctx);
ATF_TC_HEAD(libbpfjit_cop_no_ctx,tc)105 ATF_TC_HEAD(libbpfjit_cop_no_ctx, tc)
106 {
107           atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COP "
108               "instruction isn't valid without a context");
109 }
110 
ATF_TC_BODY(libbpfjit_cop_no_ctx,tc)111 ATF_TC_BODY(libbpfjit_cop_no_ctx, tc)
112 {
113           static struct bpf_insn insns[] = {
114                     BPF_STMT(BPF_MISC+BPF_COP, 0),
115                     BPF_STMT(BPF_RET+BPF_K, 7)
116           };
117 
118           bpfjit_func_t code;
119 
120           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
121 
122           ATF_CHECK(!bpf_validate(insns, insn_count));
123 
124           code = bpfjit_generate_code(NULL, insns, insn_count);
125           ATF_CHECK(code == NULL);
126 }
127 
128 ATF_TC(libbpfjit_cop_ret_A);
ATF_TC_HEAD(libbpfjit_cop_ret_A,tc)129 ATF_TC_HEAD(libbpfjit_cop_ret_A, tc)
130 {
131           atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
132               "that returns a content of the A register");
133 }
134 
ATF_TC_BODY(libbpfjit_cop_ret_A,tc)135 ATF_TC_BODY(libbpfjit_cop_ret_A, tc)
136 {
137           static struct bpf_insn insns[] = {
138                     BPF_STMT(BPF_LD+BPF_IMM, 13),
139                     BPF_STMT(BPF_MISC+BPF_COP, 0), // retA
140                     BPF_STMT(BPF_RET+BPF_A, 0)
141           };
142 
143           bpfjit_func_t code;
144           uint8_t pkt[1] = { 0 };
145           bpf_args_t args = {
146                     .pkt = pkt,
147                     .buflen = sizeof(pkt),
148                     .wirelen = sizeof(pkt),
149           };
150 
151           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
152 
153           code = bpfjit_generate_code(&ctx, insns, insn_count);
154           ATF_REQUIRE(code != NULL);
155 
156           ATF_CHECK(code(&ctx, &args) == 13);
157 
158           bpfjit_free_code(code);
159 }
160 
161 ATF_TC(libbpfjit_cop_ret_buflen);
ATF_TC_HEAD(libbpfjit_cop_ret_buflen,tc)162 ATF_TC_HEAD(libbpfjit_cop_ret_buflen, tc)
163 {
164           atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
165               "that returns the buflen argument");
166 }
167 
ATF_TC_BODY(libbpfjit_cop_ret_buflen,tc)168 ATF_TC_BODY(libbpfjit_cop_ret_buflen, tc)
169 {
170           static struct bpf_insn insns[] = {
171                     BPF_STMT(BPF_LD+BPF_IMM, 13),
172                     BPF_STMT(BPF_MISC+BPF_COP, 1), // retBL
173                     BPF_STMT(BPF_RET+BPF_A, 0)
174           };
175 
176           bpfjit_func_t code;
177           uint8_t pkt[1] = { 0 };
178           bpf_args_t args = {
179                     .pkt = pkt,
180                     .buflen = sizeof(pkt),
181                     .wirelen = sizeof(pkt)
182           };
183 
184           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
185 
186           code = bpfjit_generate_code(&ctx, insns, insn_count);
187           ATF_REQUIRE(code != NULL);
188 
189           ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
190 
191           bpfjit_free_code(code);
192 }
193 
194 ATF_TC(libbpfjit_cop_ret_wirelen);
ATF_TC_HEAD(libbpfjit_cop_ret_wirelen,tc)195 ATF_TC_HEAD(libbpfjit_cop_ret_wirelen, tc)
196 {
197           atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
198               "that returns the wirelen argument");
199 }
200 
ATF_TC_BODY(libbpfjit_cop_ret_wirelen,tc)201 ATF_TC_BODY(libbpfjit_cop_ret_wirelen, tc)
202 {
203           static struct bpf_insn insns[] = {
204                     BPF_STMT(BPF_LD+BPF_IMM, 13),
205                     BPF_STMT(BPF_MISC+BPF_COP, 2), // retWL
206                     BPF_STMT(BPF_RET+BPF_A, 0)
207           };
208 
209           bpfjit_func_t code;
210           uint8_t pkt[1] = { 0 };
211           bpf_args_t args = {
212                     .pkt = pkt,
213                     .buflen = sizeof(pkt),
214                     .wirelen = sizeof(pkt)
215           };
216 
217           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
218 
219           code = bpfjit_generate_code(&ctx, insns, insn_count);
220           ATF_REQUIRE(code != NULL);
221 
222           ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
223 
224           bpfjit_free_code(code);
225 }
226 
227 ATF_TC(libbpfjit_cop_ret_nfuncs);
ATF_TC_HEAD(libbpfjit_cop_ret_nfuncs,tc)228 ATF_TC_HEAD(libbpfjit_cop_ret_nfuncs, tc)
229 {
230           atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
231               "that returns nfuncs member of the context argument");
232 }
233 
ATF_TC_BODY(libbpfjit_cop_ret_nfuncs,tc)234 ATF_TC_BODY(libbpfjit_cop_ret_nfuncs, tc)
235 {
236           static struct bpf_insn insns[] = {
237                     BPF_STMT(BPF_LD+BPF_IMM, 13),
238                     BPF_STMT(BPF_MISC+BPF_COP, 3), // retNF
239                     BPF_STMT(BPF_RET+BPF_A, 0)
240           };
241 
242           bpfjit_func_t code;
243           uint8_t pkt[1] = { 0 };
244           bpf_args_t args = {
245                     .pkt = pkt,
246                     .buflen = sizeof(pkt),
247                     .wirelen = sizeof(pkt)
248           };
249 
250           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
251 
252           code = bpfjit_generate_code(&ctx, insns, insn_count);
253           ATF_REQUIRE(code != NULL);
254 
255           ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
256 
257           bpfjit_free_code(code);
258 }
259 
260 ATF_TC(libbpfjit_cop_side_effect);
ATF_TC_HEAD(libbpfjit_cop_side_effect,tc)261 ATF_TC_HEAD(libbpfjit_cop_side_effect, tc)
262 {
263           atf_tc_set_md_var(tc, "descr",
264               "Test that ABC optimization doesn't skip BPF_COP call");
265 }
266 
ATF_TC_BODY(libbpfjit_cop_side_effect,tc)267 ATF_TC_BODY(libbpfjit_cop_side_effect, tc)
268 {
269           static struct bpf_insn insns[] = {
270                     BPF_STMT(BPF_LD+BPF_IMM, 13),
271                     BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
272                     BPF_STMT(BPF_MISC+BPF_COP, 4), // setARG
273                     BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
274                     BPF_STMT(BPF_RET+BPF_A, 0)
275           };
276 
277           bpfjit_func_t code;
278           bool arg = false;
279           uint8_t pkt[1] = { 0 };
280           bpf_args_t args = {
281                     .pkt = pkt,
282                     .buflen = sizeof(pkt),
283                     .wirelen = sizeof(pkt),
284                     .mem = NULL,
285                     .arg = &arg
286           };
287 
288           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
289 
290           code = bpfjit_generate_code(&ctx, insns, insn_count);
291           ATF_REQUIRE(code != NULL);
292 
293           ATF_CHECK(code(&ctx, &args) == 0);
294           ATF_CHECK(arg == true);
295 
296           bpfjit_free_code(code);
297 }
298 
299 ATF_TC(libbpfjit_cop_copx);
ATF_TC_HEAD(libbpfjit_cop_copx,tc)300 ATF_TC_HEAD(libbpfjit_cop_copx, tc)
301 {
302           atf_tc_set_md_var(tc, "descr",
303               "Test BPF_COP call followed by BPF_COPX call");
304 }
305 
ATF_TC_BODY(libbpfjit_cop_copx,tc)306 ATF_TC_BODY(libbpfjit_cop_copx, tc)
307 {
308           static struct bpf_insn insns[] = {
309                     BPF_STMT(BPF_LD+BPF_IMM, 1),         /* A <- 1    */
310                     BPF_STMT(BPF_MISC+BPF_COP, 0),       /* retA      */
311                     BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
312                     BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),   /* A = P[0]  */
313                     BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
314                     BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
315                     BPF_STMT(BPF_MISC+BPF_COPX, 0),      /* retNF     */
316                     BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
317                     BPF_STMT(BPF_RET+BPF_A, 0)
318           };
319 
320           bpfjit_func_t code;
321           uint8_t pkt[1] = { 2 };
322           bpf_args_t args = {
323                     .pkt = pkt,
324                     .buflen = sizeof(pkt),
325                     .wirelen = sizeof(pkt),
326           };
327 
328           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
329 
330           code = bpfjit_generate_code(&ctx, insns, insn_count);
331           ATF_REQUIRE(code != NULL);
332 
333           ATF_CHECK(code(&ctx, &args) == 3 + ctx.nfuncs);
334 
335           bpfjit_free_code(code);
336 }
337 
338 ATF_TC(libbpfjit_cop_invalid_index);
ATF_TC_HEAD(libbpfjit_cop_invalid_index,tc)339 ATF_TC_HEAD(libbpfjit_cop_invalid_index, tc)
340 {
341           atf_tc_set_md_var(tc, "descr",
342               "Test that out-of-range coprocessor function fails validation");
343 }
344 
ATF_TC_BODY(libbpfjit_cop_invalid_index,tc)345 ATF_TC_BODY(libbpfjit_cop_invalid_index, tc)
346 {
347           static struct bpf_insn insns[] = {
348                     BPF_STMT(BPF_LD+BPF_IMM, 13),
349                     BPF_STMT(BPF_MISC+BPF_COP, 6), // invalid index
350                     BPF_STMT(BPF_RET+BPF_K, 27)
351           };
352 
353           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
354 
355           ATF_CHECK(bpfjit_generate_code(&ctx, insns, insn_count) == NULL);
356 }
357 
358 ATF_TC(libbpfjit_copx_no_ctx);
ATF_TC_HEAD(libbpfjit_copx_no_ctx,tc)359 ATF_TC_HEAD(libbpfjit_copx_no_ctx, tc)
360 {
361           atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COPX "
362               "instruction isn't valid without a context");
363 }
364 
ATF_TC_BODY(libbpfjit_copx_no_ctx,tc)365 ATF_TC_BODY(libbpfjit_copx_no_ctx, tc)
366 {
367           static struct bpf_insn insns[] = {
368                     BPF_STMT(BPF_MISC+BPF_COP, 0),
369                     BPF_STMT(BPF_RET+BPF_K, 7)
370           };
371 
372           bpfjit_func_t code;
373 
374           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
375 
376           ATF_CHECK(!bpf_validate(insns, insn_count));
377 
378           code = bpfjit_generate_code(NULL, insns, insn_count);
379           ATF_CHECK(code == NULL);
380 }
381 
382 ATF_TC(libbpfjit_copx_ret_A);
ATF_TC_HEAD(libbpfjit_copx_ret_A,tc)383 ATF_TC_HEAD(libbpfjit_copx_ret_A, tc)
384 {
385           atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
386               "that returns a content of the A register");
387 }
388 
ATF_TC_BODY(libbpfjit_copx_ret_A,tc)389 ATF_TC_BODY(libbpfjit_copx_ret_A, tc)
390 {
391           static struct bpf_insn insns[] = {
392                     BPF_STMT(BPF_LD+BPF_IMM, 13),
393                     BPF_STMT(BPF_LDX+BPF_IMM, 0), // retA
394                     BPF_STMT(BPF_MISC+BPF_COPX, 0),
395                     BPF_STMT(BPF_RET+BPF_A, 0)
396           };
397 
398           bpfjit_func_t code;
399           uint8_t pkt[1] = { 0 };
400           bpf_args_t args = {
401                     .pkt = pkt,
402                     .buflen = sizeof(pkt),
403                     .wirelen = sizeof(pkt),
404           };
405 
406           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
407 
408           code = bpfjit_generate_code(&ctx, insns, insn_count);
409           ATF_REQUIRE(code != NULL);
410 
411           ATF_CHECK(code(&ctx, &args) == 13);
412 
413           bpfjit_free_code(code);
414 }
415 
416 ATF_TC(libbpfjit_copx_ret_buflen);
ATF_TC_HEAD(libbpfjit_copx_ret_buflen,tc)417 ATF_TC_HEAD(libbpfjit_copx_ret_buflen, tc)
418 {
419           atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
420               "that returns the buflen argument");
421 }
422 
ATF_TC_BODY(libbpfjit_copx_ret_buflen,tc)423 ATF_TC_BODY(libbpfjit_copx_ret_buflen, tc)
424 {
425           static struct bpf_insn insns[] = {
426                     BPF_STMT(BPF_LD+BPF_IMM, 13),
427                     BPF_STMT(BPF_LDX+BPF_IMM, 1), // retBL
428                     BPF_STMT(BPF_MISC+BPF_COPX, 0),
429                     BPF_STMT(BPF_RET+BPF_A, 0)
430           };
431 
432           bpfjit_func_t code;
433           uint8_t pkt[1] = { 0 };
434           bpf_args_t args = {
435                     .pkt = pkt,
436                     .buflen = sizeof(pkt),
437                     .wirelen = sizeof(pkt)
438           };
439 
440           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
441 
442           code = bpfjit_generate_code(&ctx, insns, insn_count);
443           ATF_REQUIRE(code != NULL);
444 
445           ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
446 
447           bpfjit_free_code(code);
448 }
449 
450 ATF_TC(libbpfjit_copx_ret_wirelen);
ATF_TC_HEAD(libbpfjit_copx_ret_wirelen,tc)451 ATF_TC_HEAD(libbpfjit_copx_ret_wirelen, tc)
452 {
453           atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
454               "that returns the wirelen argument");
455 }
456 
ATF_TC_BODY(libbpfjit_copx_ret_wirelen,tc)457 ATF_TC_BODY(libbpfjit_copx_ret_wirelen, tc)
458 {
459           static struct bpf_insn insns[] = {
460                     BPF_STMT(BPF_LDX+BPF_IMM, 2), // retWL
461                     BPF_STMT(BPF_LD+BPF_IMM, 13),
462                     BPF_STMT(BPF_MISC+BPF_COPX, 0),
463                     BPF_STMT(BPF_RET+BPF_A, 0)
464           };
465 
466           bpfjit_func_t code;
467           uint8_t pkt[1] = { 0 };
468           bpf_args_t args = {
469                     .pkt = pkt,
470                     .buflen = sizeof(pkt),
471                     .wirelen = sizeof(pkt)
472           };
473 
474           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
475 
476           code = bpfjit_generate_code(&ctx, insns, insn_count);
477           ATF_REQUIRE(code != NULL);
478 
479           ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
480 
481           bpfjit_free_code(code);
482 }
483 
484 ATF_TC(libbpfjit_copx_ret_nfuncs);
ATF_TC_HEAD(libbpfjit_copx_ret_nfuncs,tc)485 ATF_TC_HEAD(libbpfjit_copx_ret_nfuncs, tc)
486 {
487           atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
488               "that returns nfuncs member of the context argument");
489 }
490 
ATF_TC_BODY(libbpfjit_copx_ret_nfuncs,tc)491 ATF_TC_BODY(libbpfjit_copx_ret_nfuncs, tc)
492 {
493           static struct bpf_insn insns[] = {
494                     BPF_STMT(BPF_LD+BPF_IMM, 13),
495                     BPF_STMT(BPF_LDX+BPF_IMM, 3), // retNF
496                     BPF_STMT(BPF_MISC+BPF_COPX, 0),
497                     BPF_STMT(BPF_RET+BPF_A, 0)
498           };
499 
500           bpfjit_func_t code;
501           uint8_t pkt[1] = { 0 };
502           bpf_args_t args = {
503                     .pkt = pkt,
504                     .buflen = sizeof(pkt),
505                     .wirelen = sizeof(pkt)
506           };
507 
508           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
509 
510           code = bpfjit_generate_code(&ctx, insns, insn_count);
511           ATF_REQUIRE(code != NULL);
512 
513           ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
514 
515           bpfjit_free_code(code);
516 }
517 
518 ATF_TC(libbpfjit_copx_side_effect);
ATF_TC_HEAD(libbpfjit_copx_side_effect,tc)519 ATF_TC_HEAD(libbpfjit_copx_side_effect, tc)
520 {
521           atf_tc_set_md_var(tc, "descr",
522               "Test that ABC optimization doesn't skip BPF_COPX call");
523 }
524 
ATF_TC_BODY(libbpfjit_copx_side_effect,tc)525 ATF_TC_BODY(libbpfjit_copx_side_effect, tc)
526 {
527           static struct bpf_insn insns[] = {
528                     BPF_STMT(BPF_LD+BPF_IMM, 13),
529                     BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
530                     BPF_STMT(BPF_LDX+BPF_IMM, 4), // setARG
531                     BPF_STMT(BPF_MISC+BPF_COPX, 0),
532                     BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
533                     BPF_STMT(BPF_RET+BPF_A, 0)
534           };
535 
536           bpfjit_func_t code;
537           bool arg = false;
538           uint8_t pkt[1] = { 0 };
539           bpf_args_t args = {
540                     .pkt = pkt,
541                     .buflen = sizeof(pkt),
542                     .wirelen = sizeof(pkt),
543                     .mem = NULL,
544                     .arg = &arg
545           };
546 
547           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
548 
549           code = bpfjit_generate_code(&ctx, insns, insn_count);
550           ATF_REQUIRE(code != NULL);
551 
552           ATF_CHECK(code(&ctx, &args) == 0);
553           ATF_CHECK(arg == true);
554 
555           bpfjit_free_code(code);
556 }
557 
558 ATF_TC(libbpfjit_copx_cop);
ATF_TC_HEAD(libbpfjit_copx_cop,tc)559 ATF_TC_HEAD(libbpfjit_copx_cop, tc)
560 {
561           atf_tc_set_md_var(tc, "descr",
562               "Test BPF_COPX call followed by BPF_COP call");
563 }
564 
ATF_TC_BODY(libbpfjit_copx_cop,tc)565 ATF_TC_BODY(libbpfjit_copx_cop, tc)
566 {
567           static struct bpf_insn insns[] = {
568                     BPF_STMT(BPF_LDX+BPF_IMM, 2),        /* X <- 2    */
569                     BPF_STMT(BPF_MISC+BPF_COPX, 0),      /* retWL     */
570                     BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
571                     BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
572                     BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),   /* A = P[0]  */
573                     BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
574                     BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
575                     BPF_STMT(BPF_MISC+BPF_COP, 3),      /* retNF     */
576                     BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
577                     BPF_STMT(BPF_RET+BPF_A, 0)
578           };
579 
580           bpfjit_func_t code;
581           uint8_t pkt[1] = { 2 };
582           bpf_args_t args = {
583                     .pkt = pkt,
584                     .buflen = sizeof(pkt),
585                     .wirelen = sizeof(pkt),
586           };
587 
588           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
589 
590           code = bpfjit_generate_code(&ctx, insns, insn_count);
591           ATF_REQUIRE(code != NULL);
592 
593           ATF_CHECK(code(&ctx, &args) == 5 + ctx.nfuncs);
594 
595           bpfjit_free_code(code);
596 }
597 
598 ATF_TC(libbpfjit_copx_invalid_index);
ATF_TC_HEAD(libbpfjit_copx_invalid_index,tc)599 ATF_TC_HEAD(libbpfjit_copx_invalid_index, tc)
600 {
601           atf_tc_set_md_var(tc, "descr",
602               "Test that out-of-range BPF_COPX call fails at runtime");
603 }
604 
ATF_TC_BODY(libbpfjit_copx_invalid_index,tc)605 ATF_TC_BODY(libbpfjit_copx_invalid_index, tc)
606 {
607           static struct bpf_insn insns[] = {
608                     BPF_STMT(BPF_LDX+BPF_IMM, 5), // invalid index
609                     BPF_STMT(BPF_MISC+BPF_COPX, 0),
610                     BPF_STMT(BPF_RET+BPF_K, 27)
611           };
612 
613           bpfjit_func_t code;
614           uint8_t pkt[1] = { 0 };
615           bpf_args_t args = {
616                     .pkt = pkt,
617                     .buflen = sizeof(pkt),
618                     .wirelen = sizeof(pkt)
619           };
620 
621           size_t insn_count = sizeof(insns) / sizeof(insns[0]);
622 
623           code = bpfjit_generate_code(&ctx, insns, insn_count);
624           ATF_REQUIRE(code != NULL);
625 
626           ATF_CHECK(code(&ctx, &args) == 0);
627 
628           bpfjit_free_code(code);
629 }
630 
ATF_TP_ADD_TCS(tp)631 ATF_TP_ADD_TCS(tp)
632 {
633 
634           /*
635            * For every new test please also add a similar test
636            * to ../../net/bpfjit/t_cop.c
637            */
638           ATF_TP_ADD_TC(tp, libbpfjit_cop_no_ctx);
639           ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_A);
640           ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_buflen);
641           ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_wirelen);
642           ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_nfuncs);
643           ATF_TP_ADD_TC(tp, libbpfjit_cop_side_effect);
644           ATF_TP_ADD_TC(tp, libbpfjit_cop_copx);
645           ATF_TP_ADD_TC(tp, libbpfjit_cop_invalid_index);
646 
647           ATF_TP_ADD_TC(tp, libbpfjit_copx_no_ctx);
648           ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_A);
649           ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_buflen);
650           ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_wirelen);
651           ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_nfuncs);
652           ATF_TP_ADD_TC(tp, libbpfjit_copx_side_effect);
653           ATF_TP_ADD_TC(tp, libbpfjit_copx_cop);
654           ATF_TP_ADD_TC(tp, libbpfjit_copx_invalid_index);
655 
656           return atf_no_error();
657 }
658