1 /*	$NetBSD: t_cop.c,v 1.4 2017/01/13 21:30:42 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 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 2017/01/13 21:30:42 christos Exp $");
34 
35 #include <stdint.h>
36 #include <string.h>
37 
38 #define __BPF_PRIVATE
39 #include <net/bpf.h>
40 #include <net/bpfjit.h>
41 
42 #include "../../net/bpf/h_bpf.h"
43 
44 /* XXX: atf-c.h has collisions with mbuf */
45 #undef m_type
46 #undef m_data
47 #include <atf-c.h>
48 
49 #include "h_macros.h"
50 
51 static uint32_t retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
52 static uint32_t retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
53 static uint32_t retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
54 static uint32_t retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
55 static uint32_t setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
56 
57 static const bpf_copfunc_t copfuncs[] = {
58 	&retA,
59 	&retBL,
60 	&retWL,
61 	&retNF,
62 	&setARG
63 };
64 
65 static const bpf_ctx_t ctx = {
66 	.copfuncs = copfuncs,
67 	.nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
68 	.extwords = 0
69 };
70 
71 static uint32_t
72 retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
73 {
74 
75 	return A;
76 }
77 
78 static uint32_t
79 retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
80 {
81 
82 	return args->buflen;
83 }
84 
85 static uint32_t
86 retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
87 {
88 
89 	return args->wirelen;
90 }
91 
92 static uint32_t
93 retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
94 {
95 
96 	return bc->nfuncs;
97 }
98 
99 /*
100  * COP function with a side effect.
101  */
102 static uint32_t
103 setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
104 {
105 	bool *arg = (bool *)args->arg;
106 	bool old = *arg;
107 
108 	*arg = true;
109 	return old;
110 }
111 
112 ATF_TC(bpfjit_cop_no_ctx);
113 ATF_TC_HEAD(bpfjit_cop_no_ctx, tc)
114 {
115 	atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COP "
116 	    "instruction isn't valid without a context");
117 }
118 
119 ATF_TC_BODY(bpfjit_cop_no_ctx, tc)
120 {
121 	static struct bpf_insn insns[] = {
122 		BPF_STMT(BPF_MISC+BPF_COP, 0),
123 		BPF_STMT(BPF_RET+BPF_K, 7)
124 	};
125 
126 	bpfjit_func_t code;
127 
128 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
129 
130 	RZ(rump_init());
131 
132 	ATF_CHECK(!prog_validate(insns, insn_count));
133 
134 	rump_schedule();
135 	code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
136 	rump_unschedule();
137 	ATF_CHECK(code == NULL);
138 }
139 
140 ATF_TC(bpfjit_cop_ret_A);
141 ATF_TC_HEAD(bpfjit_cop_ret_A, tc)
142 {
143 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
144 	    "that returns a content of the A register");
145 }
146 
147 ATF_TC_BODY(bpfjit_cop_ret_A, tc)
148 {
149 	static struct bpf_insn insns[] = {
150 		BPF_STMT(BPF_LD+BPF_IMM, 13),
151 		BPF_STMT(BPF_MISC+BPF_COP, 0), // retA
152 		BPF_STMT(BPF_RET+BPF_A, 0)
153 	};
154 
155 	bpfjit_func_t code;
156 	uint8_t pkt[1] = { 0 };
157 	bpf_args_t args = {
158 		.pkt = pkt,
159 		.buflen = sizeof(pkt),
160 		.wirelen = sizeof(pkt),
161 	};
162 
163 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
164 
165 	RZ(rump_init());
166 
167 	rump_schedule();
168 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
169 	rump_unschedule();
170 	ATF_REQUIRE(code != NULL);
171 
172 	ATF_CHECK(code(&ctx, &args) == 13);
173 
174 	rump_schedule();
175 	rumpns_bpfjit_free_code(code);
176 	rump_unschedule();
177 }
178 
179 ATF_TC(bpfjit_cop_ret_buflen);
180 ATF_TC_HEAD(bpfjit_cop_ret_buflen, tc)
181 {
182 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
183 	    "that returns the buflen argument");
184 }
185 
186 ATF_TC_BODY(bpfjit_cop_ret_buflen, tc)
187 {
188 	static struct bpf_insn insns[] = {
189 		BPF_STMT(BPF_LD+BPF_IMM, 13),
190 		BPF_STMT(BPF_MISC+BPF_COP, 1), // retBL
191 		BPF_STMT(BPF_RET+BPF_A, 0)
192 	};
193 
194 	bpfjit_func_t code;
195 	uint8_t pkt[1] = { 0 };
196 	bpf_args_t args = {
197 		.pkt = pkt,
198 		.buflen = sizeof(pkt),
199 		.wirelen = sizeof(pkt)
200 	};
201 
202 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
203 
204 	RZ(rump_init());
205 
206 	rump_schedule();
207 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
208 	rump_unschedule();
209 	ATF_REQUIRE(code != NULL);
210 
211 	ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
212 
213 	rump_schedule();
214 	rumpns_bpfjit_free_code(code);
215 	rump_unschedule();
216 }
217 
218 ATF_TC(bpfjit_cop_ret_wirelen);
219 ATF_TC_HEAD(bpfjit_cop_ret_wirelen, tc)
220 {
221 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
222 	    "that returns the wirelen argument");
223 }
224 
225 ATF_TC_BODY(bpfjit_cop_ret_wirelen, tc)
226 {
227 	static struct bpf_insn insns[] = {
228 		BPF_STMT(BPF_LD+BPF_IMM, 13),
229 		BPF_STMT(BPF_MISC+BPF_COP, 2), // retWL
230 		BPF_STMT(BPF_RET+BPF_A, 0)
231 	};
232 
233 	bpfjit_func_t code;
234 	uint8_t pkt[1] = { 0 };
235 	bpf_args_t args = {
236 		.pkt = pkt,
237 		.buflen = sizeof(pkt),
238 		.wirelen = sizeof(pkt)
239 	};
240 
241 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
242 
243 	RZ(rump_init());
244 
245 	rump_schedule();
246 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
247 	rump_unschedule();
248 	ATF_REQUIRE(code != NULL);
249 
250 	ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
251 
252 	rump_schedule();
253 	rumpns_bpfjit_free_code(code);
254 	rump_unschedule();
255 }
256 
257 ATF_TC(bpfjit_cop_ret_nfuncs);
258 ATF_TC_HEAD(bpfjit_cop_ret_nfuncs, tc)
259 {
260 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
261 	    "that returns nfuncs member of the context argument");
262 }
263 
264 ATF_TC_BODY(bpfjit_cop_ret_nfuncs, tc)
265 {
266 	static struct bpf_insn insns[] = {
267 		BPF_STMT(BPF_LD+BPF_IMM, 13),
268 		BPF_STMT(BPF_MISC+BPF_COP, 3), // retNF
269 		BPF_STMT(BPF_RET+BPF_A, 0)
270 	};
271 
272 	bpfjit_func_t code;
273 	uint8_t pkt[1] = { 0 };
274 	bpf_args_t args = {
275 		.pkt = pkt,
276 		.buflen = sizeof(pkt),
277 		.wirelen = sizeof(pkt)
278 	};
279 
280 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
281 
282 	RZ(rump_init());
283 
284 	rump_schedule();
285 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
286 	rump_unschedule();
287 	ATF_REQUIRE(code != NULL);
288 
289 	ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
290 
291 	rump_schedule();
292 	rumpns_bpfjit_free_code(code);
293 	rump_unschedule();
294 }
295 
296 ATF_TC(bpfjit_cop_side_effect);
297 ATF_TC_HEAD(bpfjit_cop_side_effect, tc)
298 {
299 	atf_tc_set_md_var(tc, "descr",
300 	    "Test that ABC optimization doesn't skip BPF_COP call");
301 }
302 
303 ATF_TC_BODY(bpfjit_cop_side_effect, tc)
304 {
305 	static struct bpf_insn insns[] = {
306 		BPF_STMT(BPF_LD+BPF_IMM, 13),
307 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
308 		BPF_STMT(BPF_MISC+BPF_COP, 4), // setARG
309 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
310 		BPF_STMT(BPF_RET+BPF_A, 0)
311 	};
312 
313 	bpfjit_func_t code;
314 	bool arg = false;
315 	uint8_t pkt[1] = { 0 };
316 	bpf_args_t args = {
317 		.pkt = pkt,
318 		.buflen = sizeof(pkt),
319 		.wirelen = sizeof(pkt),
320 		.mem = NULL,
321 		.arg = &arg
322 	};
323 
324 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
325 
326 	RZ(rump_init());
327 
328 	rump_schedule();
329 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
330 	rump_unschedule();
331 	ATF_REQUIRE(code != NULL);
332 
333 	ATF_CHECK(code(&ctx, &args) == 0);
334 	ATF_CHECK(arg == true);
335 
336 	rump_schedule();
337 	rumpns_bpfjit_free_code(code);
338 	rump_unschedule();
339 }
340 
341 ATF_TC(bpfjit_cop_copx);
342 ATF_TC_HEAD(bpfjit_cop_copx, tc)
343 {
344 	atf_tc_set_md_var(tc, "descr",
345 	    "Test BPF_COP call followed by BPF_COPX call");
346 }
347 
348 ATF_TC_BODY(bpfjit_cop_copx, tc)
349 {
350 	static struct bpf_insn insns[] = {
351 		BPF_STMT(BPF_LD+BPF_IMM, 1),         /* A <- 1    */
352 		BPF_STMT(BPF_MISC+BPF_COP, 0),       /* retA      */
353 		BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
354 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),   /* A = P[0]  */
355 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
356 		BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
357 		BPF_STMT(BPF_MISC+BPF_COPX, 0),      /* retNF     */
358 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
359 		BPF_STMT(BPF_RET+BPF_A, 0)
360 	};
361 
362 	bpfjit_func_t code;
363 	uint8_t pkt[1] = { 2 };
364 	bpf_args_t args = {
365 		.pkt = pkt,
366 		.buflen = sizeof(pkt),
367 		.wirelen = sizeof(pkt),
368 	};
369 
370 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
371 
372 	RZ(rump_init());
373 
374 	rump_schedule();
375 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
376 	rump_unschedule();
377 	ATF_REQUIRE(code != NULL);
378 
379 	ATF_CHECK(code(&ctx, &args) == 3 + ctx.nfuncs);
380 
381 	rump_schedule();
382 	rumpns_bpfjit_free_code(code);
383 	rump_unschedule();
384 }
385 
386 ATF_TC(bpfjit_cop_invalid_index);
387 ATF_TC_HEAD(bpfjit_cop_invalid_index, tc)
388 {
389 	atf_tc_set_md_var(tc, "descr",
390 	    "Test that out-of-range coprocessor function fails validation");
391 }
392 
393 ATF_TC_BODY(bpfjit_cop_invalid_index, tc)
394 {
395 	static struct bpf_insn insns[] = {
396 		BPF_STMT(BPF_LD+BPF_IMM, 13),
397 		BPF_STMT(BPF_MISC+BPF_COP, 6), // invalid index
398 		BPF_STMT(BPF_RET+BPF_K, 27)
399 	};
400 
401 	bpfjit_func_t code;
402 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
403 
404 	RZ(rump_init());
405 
406 	rump_schedule();
407 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
408 	rump_unschedule();
409 	ATF_CHECK(code == NULL);
410 }
411 
412 ATF_TC(bpfjit_copx_no_ctx);
413 ATF_TC_HEAD(bpfjit_copx_no_ctx, tc)
414 {
415 	atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COPX "
416 	    "instruction isn't valid without a context");
417 }
418 
419 ATF_TC_BODY(bpfjit_copx_no_ctx, tc)
420 {
421 	static struct bpf_insn insns[] = {
422 		BPF_STMT(BPF_MISC+BPF_COP, 0),
423 		BPF_STMT(BPF_RET+BPF_K, 7)
424 	};
425 
426 	bpfjit_func_t code;
427 
428 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
429 
430 	RZ(rump_init());
431 
432 	ATF_CHECK(!prog_validate(insns, insn_count));
433 
434 	rump_schedule();
435 	code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
436 	rump_unschedule();
437 	ATF_CHECK(code == NULL);
438 }
439 
440 ATF_TC(bpfjit_copx_ret_A);
441 ATF_TC_HEAD(bpfjit_copx_ret_A, tc)
442 {
443 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
444 	    "that returns a content of the A register");
445 }
446 
447 ATF_TC_BODY(bpfjit_copx_ret_A, tc)
448 {
449 	static struct bpf_insn insns[] = {
450 		BPF_STMT(BPF_LD+BPF_IMM, 13),
451 		BPF_STMT(BPF_LDX+BPF_IMM, 0), // retA
452 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
453 		BPF_STMT(BPF_RET+BPF_A, 0)
454 	};
455 
456 	bpfjit_func_t code;
457 	uint8_t pkt[1] = { 0 };
458 	bpf_args_t args = {
459 		.pkt = pkt,
460 		.buflen = sizeof(pkt),
461 		.wirelen = sizeof(pkt),
462 	};
463 
464 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
465 
466 	RZ(rump_init());
467 
468 	rump_schedule();
469 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
470 	rump_unschedule();
471 	ATF_REQUIRE(code != NULL);
472 
473 	ATF_CHECK(code(&ctx, &args) == 13);
474 
475 	rump_schedule();
476 	rumpns_bpfjit_free_code(code);
477 	rump_unschedule();
478 }
479 
480 ATF_TC(bpfjit_copx_ret_buflen);
481 ATF_TC_HEAD(bpfjit_copx_ret_buflen, tc)
482 {
483 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
484 	    "that returns the buflen argument");
485 }
486 
487 ATF_TC_BODY(bpfjit_copx_ret_buflen, tc)
488 {
489 	static struct bpf_insn insns[] = {
490 		BPF_STMT(BPF_LD+BPF_IMM, 13),
491 		BPF_STMT(BPF_LDX+BPF_IMM, 1), // retBL
492 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
493 		BPF_STMT(BPF_RET+BPF_A, 0)
494 	};
495 
496 	bpfjit_func_t code;
497 	uint8_t pkt[1] = { 0 };
498 	bpf_args_t args = {
499 		.pkt = pkt,
500 		.buflen = sizeof(pkt),
501 		.wirelen = sizeof(pkt)
502 	};
503 
504 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
505 
506 	RZ(rump_init());
507 
508 	rump_schedule();
509 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
510 	rump_unschedule();
511 	ATF_REQUIRE(code != NULL);
512 
513 	ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
514 
515 	rump_schedule();
516 	rumpns_bpfjit_free_code(code);
517 	rump_unschedule();
518 }
519 
520 ATF_TC(bpfjit_copx_ret_wirelen);
521 ATF_TC_HEAD(bpfjit_copx_ret_wirelen, tc)
522 {
523 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
524 	    "that returns the wirelen argument");
525 }
526 
527 ATF_TC_BODY(bpfjit_copx_ret_wirelen, tc)
528 {
529 	static struct bpf_insn insns[] = {
530 		BPF_STMT(BPF_LDX+BPF_IMM, 2), // retWL
531 		BPF_STMT(BPF_LD+BPF_IMM, 13),
532 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
533 		BPF_STMT(BPF_RET+BPF_A, 0)
534 	};
535 
536 	bpfjit_func_t code;
537 	uint8_t pkt[1] = { 0 };
538 	bpf_args_t args = {
539 		.pkt = pkt,
540 		.buflen = sizeof(pkt),
541 		.wirelen = sizeof(pkt)
542 	};
543 
544 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
545 
546 	RZ(rump_init());
547 
548 	rump_schedule();
549 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
550 	rump_unschedule();
551 	ATF_REQUIRE(code != NULL);
552 
553 	ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
554 
555 	rump_schedule();
556 	rumpns_bpfjit_free_code(code);
557 	rump_unschedule();
558 }
559 
560 ATF_TC(bpfjit_copx_ret_nfuncs);
561 ATF_TC_HEAD(bpfjit_copx_ret_nfuncs, tc)
562 {
563 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
564 	    "that returns nfuncs member of the context argument");
565 }
566 
567 ATF_TC_BODY(bpfjit_copx_ret_nfuncs, tc)
568 {
569 	static struct bpf_insn insns[] = {
570 		BPF_STMT(BPF_LD+BPF_IMM, 13),
571 		BPF_STMT(BPF_LDX+BPF_IMM, 3), // retNF
572 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
573 		BPF_STMT(BPF_RET+BPF_A, 0)
574 	};
575 
576 	bpfjit_func_t code;
577 	uint8_t pkt[1] = { 0 };
578 	bpf_args_t args = {
579 		.pkt = pkt,
580 		.buflen = sizeof(pkt),
581 		.wirelen = sizeof(pkt)
582 	};
583 
584 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
585 
586 	RZ(rump_init());
587 
588 	rump_schedule();
589 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
590 	rump_unschedule();
591 	ATF_REQUIRE(code != NULL);
592 
593 	ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
594 
595 	rump_schedule();
596 	rumpns_bpfjit_free_code(code);
597 	rump_unschedule();
598 }
599 
600 ATF_TC(bpfjit_copx_side_effect);
601 ATF_TC_HEAD(bpfjit_copx_side_effect, tc)
602 {
603 	atf_tc_set_md_var(tc, "descr",
604 	    "Test that ABC optimization doesn't skip BPF_COPX call");
605 }
606 
607 ATF_TC_BODY(bpfjit_copx_side_effect, tc)
608 {
609 	static struct bpf_insn insns[] = {
610 		BPF_STMT(BPF_LD+BPF_IMM, 13),
611 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
612 		BPF_STMT(BPF_LDX+BPF_IMM, 4), // setARG
613 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
614 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
615 		BPF_STMT(BPF_RET+BPF_A, 0)
616 	};
617 
618 	bpfjit_func_t code;
619 	bool arg = false;
620 	uint8_t pkt[1] = { 0 };
621 	bpf_args_t args = {
622 		.pkt = pkt,
623 		.buflen = sizeof(pkt),
624 		.wirelen = sizeof(pkt),
625 		.mem = NULL,
626 		.arg = &arg
627 	};
628 
629 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
630 
631 	RZ(rump_init());
632 
633 	rump_schedule();
634 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
635 	rump_unschedule();
636 	ATF_REQUIRE(code != NULL);
637 
638 	ATF_CHECK(code(&ctx, &args) == 0);
639 	ATF_CHECK(arg == true);
640 
641 	rump_schedule();
642 	rumpns_bpfjit_free_code(code);
643 	rump_unschedule();
644 }
645 
646 ATF_TC(bpfjit_copx_cop);
647 ATF_TC_HEAD(bpfjit_copx_cop, tc)
648 {
649 	atf_tc_set_md_var(tc, "descr",
650 	    "Test BPF_COPX call followed by BPF_COP call");
651 }
652 
653 ATF_TC_BODY(bpfjit_copx_cop, tc)
654 {
655 	static struct bpf_insn insns[] = {
656 		BPF_STMT(BPF_LDX+BPF_IMM, 2),        /* X <- 2    */
657 		BPF_STMT(BPF_MISC+BPF_COPX, 0),      /* retWL     */
658 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
659 		BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
660 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),   /* A = P[0]  */
661 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
662 		BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
663 		BPF_STMT(BPF_MISC+BPF_COP, 3),      /* retNF     */
664 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
665 		BPF_STMT(BPF_RET+BPF_A, 0)
666 	};
667 
668 	bpfjit_func_t code;
669 	uint8_t pkt[1] = { 2 };
670 	bpf_args_t args = {
671 		.pkt = pkt,
672 		.buflen = sizeof(pkt),
673 		.wirelen = sizeof(pkt),
674 	};
675 
676 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
677 
678 	RZ(rump_init());
679 
680 	rump_schedule();
681 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
682 	rump_unschedule();
683 	ATF_REQUIRE(code != NULL);
684 
685 	ATF_CHECK(code(&ctx, &args) == 5 + ctx.nfuncs);
686 
687 	rump_schedule();
688 	rumpns_bpfjit_free_code(code);
689 	rump_unschedule();
690 }
691 
692 ATF_TC(bpfjit_copx_invalid_index);
693 ATF_TC_HEAD(bpfjit_copx_invalid_index, tc)
694 {
695 	atf_tc_set_md_var(tc, "descr",
696 	    "Test that out-of-range BPF_COPX call fails at runtime");
697 }
698 
699 ATF_TC_BODY(bpfjit_copx_invalid_index, tc)
700 {
701 	static struct bpf_insn insns[] = {
702 		BPF_STMT(BPF_LDX+BPF_IMM, 5), // invalid index
703 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
704 		BPF_STMT(BPF_RET+BPF_K, 27)
705 	};
706 
707 	bpfjit_func_t code;
708 	uint8_t pkt[1] = { 0 };
709 	bpf_args_t args = {
710 		.pkt = pkt,
711 		.buflen = sizeof(pkt),
712 		.wirelen = sizeof(pkt)
713 	};
714 
715 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
716 
717 	RZ(rump_init());
718 
719 	rump_schedule();
720 	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
721 	rump_unschedule();
722 	ATF_REQUIRE(code != NULL);
723 
724 	ATF_CHECK(code(&ctx, &args) == 0);
725 
726 	rump_schedule();
727 	rumpns_bpfjit_free_code(code);
728 	rump_unschedule();
729 }
730 
731 ATF_TP_ADD_TCS(tp)
732 {
733 
734 	/*
735 	 * For every new test please also add a similar test
736 	 * to ../../lib/libbpfjit/t_cop.c
737 	 */
738 	ATF_TP_ADD_TC(tp, bpfjit_cop_no_ctx);
739 	ATF_TP_ADD_TC(tp, bpfjit_cop_ret_A);
740 	ATF_TP_ADD_TC(tp, bpfjit_cop_ret_buflen);
741 	ATF_TP_ADD_TC(tp, bpfjit_cop_ret_wirelen);
742 	ATF_TP_ADD_TC(tp, bpfjit_cop_ret_nfuncs);
743 	ATF_TP_ADD_TC(tp, bpfjit_cop_side_effect);
744 	ATF_TP_ADD_TC(tp, bpfjit_cop_copx);
745 	ATF_TP_ADD_TC(tp, bpfjit_cop_invalid_index);
746 
747 	ATF_TP_ADD_TC(tp, bpfjit_copx_no_ctx);
748 	ATF_TP_ADD_TC(tp, bpfjit_copx_ret_A);
749 	ATF_TP_ADD_TC(tp, bpfjit_copx_ret_buflen);
750 	ATF_TP_ADD_TC(tp, bpfjit_copx_ret_wirelen);
751 	ATF_TP_ADD_TC(tp, bpfjit_copx_ret_nfuncs);
752 	ATF_TP_ADD_TC(tp, bpfjit_copx_side_effect);
753 	ATF_TP_ADD_TC(tp, bpfjit_copx_cop);
754 	ATF_TP_ADD_TC(tp, bpfjit_copx_invalid_index);
755 
756 	return atf_no_error();
757 }
758