t_cop.c revision 314817
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
51static uint32_t retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
52static uint32_t retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
53static uint32_t retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
54static uint32_t retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
55static uint32_t setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
56
57static const bpf_copfunc_t copfuncs[] = {
58	&retA,
59	&retBL,
60	&retWL,
61	&retNF,
62	&setARG
63};
64
65static const bpf_ctx_t ctx = {
66	.copfuncs = copfuncs,
67	.nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
68	.extwords = 0
69};
70
71static uint32_t
72retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
73{
74
75	return A;
76}
77
78static uint32_t
79retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
80{
81
82	return args->buflen;
83}
84
85static uint32_t
86retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
87{
88
89	return args->wirelen;
90}
91
92static uint32_t
93retNF(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 */
102static uint32_t
103setARG(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
112ATF_TC(bpfjit_cop_no_ctx);
113ATF_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
119ATF_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
140ATF_TC(bpfjit_cop_ret_A);
141ATF_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
147ATF_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
179ATF_TC(bpfjit_cop_ret_buflen);
180ATF_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
186ATF_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
218ATF_TC(bpfjit_cop_ret_wirelen);
219ATF_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
225ATF_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
257ATF_TC(bpfjit_cop_ret_nfuncs);
258ATF_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
264ATF_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
296ATF_TC(bpfjit_cop_side_effect);
297ATF_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
303ATF_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
341ATF_TC(bpfjit_cop_copx);
342ATF_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
348ATF_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
386ATF_TC(bpfjit_cop_invalid_index);
387ATF_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
393ATF_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
412ATF_TC(bpfjit_copx_no_ctx);
413ATF_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
419ATF_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
440ATF_TC(bpfjit_copx_ret_A);
441ATF_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
447ATF_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
480ATF_TC(bpfjit_copx_ret_buflen);
481ATF_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
487ATF_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
520ATF_TC(bpfjit_copx_ret_wirelen);
521ATF_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
527ATF_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
560ATF_TC(bpfjit_copx_ret_nfuncs);
561ATF_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
567ATF_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
600ATF_TC(bpfjit_copx_side_effect);
601ATF_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
607ATF_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
646ATF_TC(bpfjit_copx_cop);
647ATF_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
653ATF_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
692ATF_TC(bpfjit_copx_invalid_index);
693ATF_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
699ATF_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
731ATF_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