xref: /netbsd-src/tests/lib/libbpfjit/t_cop.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: t_cop.c,v 1.2 2014/06/25 18:16:40 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.2 2014/06/25 18:16:40 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
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
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
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
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
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(bpfjit_cop_no_ctx);
105 ATF_TC_HEAD(bpfjit_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 
111 ATF_TC_BODY(bpfjit_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(bpfjit_cop_ret_A);
129 ATF_TC_HEAD(bpfjit_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 
135 ATF_TC_BODY(bpfjit_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(bpfjit_cop_ret_buflen);
162 ATF_TC_HEAD(bpfjit_cop_ret_buflen, tc)
163 {
164 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
165 	    "that returns the buflen argument");
166 }
167 
168 ATF_TC_BODY(bpfjit_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(bpfjit_cop_ret_wirelen);
195 ATF_TC_HEAD(bpfjit_cop_ret_wirelen, tc)
196 {
197 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
198 	    "that returns the wirelen argument");
199 }
200 
201 ATF_TC_BODY(bpfjit_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(bpfjit_cop_ret_nfuncs);
228 ATF_TC_HEAD(bpfjit_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 
234 ATF_TC_BODY(bpfjit_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(bpfjit_cop_side_effect);
261 ATF_TC_HEAD(bpfjit_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 
267 ATF_TC_BODY(bpfjit_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(bpfjit_cop_invalid_index);
300 ATF_TC_HEAD(bpfjit_cop_invalid_index, tc)
301 {
302 	atf_tc_set_md_var(tc, "descr",
303 	    "Test that out-of-range coprocessor function fails validation");
304 }
305 
306 ATF_TC_BODY(bpfjit_cop_invalid_index, tc)
307 {
308 	static struct bpf_insn insns[] = {
309 		BPF_STMT(BPF_LD+BPF_IMM, 13),
310 		BPF_STMT(BPF_MISC+BPF_COP, 6), // invalid index
311 		BPF_STMT(BPF_RET+BPF_K, 27)
312 	};
313 
314 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
315 
316 	ATF_CHECK(bpfjit_generate_code(&ctx, insns, insn_count) == NULL);
317 }
318 
319 ATF_TC(bpfjit_copx_no_ctx);
320 ATF_TC_HEAD(bpfjit_copx_no_ctx, tc)
321 {
322 	atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COPX "
323 	    "instruction isn't valid without a context");
324 }
325 
326 ATF_TC_BODY(bpfjit_copx_no_ctx, tc)
327 {
328 	static struct bpf_insn insns[] = {
329 		BPF_STMT(BPF_MISC+BPF_COP, 0),
330 		BPF_STMT(BPF_RET+BPF_K, 7)
331 	};
332 
333 	bpfjit_func_t code;
334 
335 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
336 
337 	ATF_CHECK(!bpf_validate(insns, insn_count));
338 
339 	code = bpfjit_generate_code(NULL, insns, insn_count);
340 	ATF_CHECK(code == NULL);
341 }
342 
343 ATF_TC(bpfjit_copx_ret_A);
344 ATF_TC_HEAD(bpfjit_copx_ret_A, tc)
345 {
346 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
347 	    "that returns a content of the A register");
348 }
349 
350 ATF_TC_BODY(bpfjit_copx_ret_A, tc)
351 {
352 	static struct bpf_insn insns[] = {
353 		BPF_STMT(BPF_LD+BPF_IMM, 13),
354 		BPF_STMT(BPF_LDX+BPF_IMM, 0), // retA
355 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
356 		BPF_STMT(BPF_RET+BPF_A, 0)
357 	};
358 
359 	bpfjit_func_t code;
360 	uint8_t pkt[1] = { 0 };
361 	bpf_args_t args = {
362 		.pkt = pkt,
363 		.buflen = sizeof(pkt),
364 		.wirelen = sizeof(pkt),
365 	};
366 
367 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
368 
369 	code = bpfjit_generate_code(&ctx, insns, insn_count);
370 	ATF_REQUIRE(code != NULL);
371 
372 	ATF_CHECK(code(&ctx, &args) == 13);
373 
374 	bpfjit_free_code(code);
375 }
376 
377 ATF_TC(bpfjit_copx_ret_buflen);
378 ATF_TC_HEAD(bpfjit_copx_ret_buflen, tc)
379 {
380 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
381 	    "that returns the buflen argument");
382 }
383 
384 ATF_TC_BODY(bpfjit_copx_ret_buflen, tc)
385 {
386 	static struct bpf_insn insns[] = {
387 		BPF_STMT(BPF_LD+BPF_IMM, 13),
388 		BPF_STMT(BPF_LDX+BPF_IMM, 1), // retBL
389 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
390 		BPF_STMT(BPF_RET+BPF_A, 0)
391 	};
392 
393 	bpfjit_func_t code;
394 	uint8_t pkt[1] = { 0 };
395 	bpf_args_t args = {
396 		.pkt = pkt,
397 		.buflen = sizeof(pkt),
398 		.wirelen = sizeof(pkt)
399 	};
400 
401 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
402 
403 	code = bpfjit_generate_code(&ctx, insns, insn_count);
404 	ATF_REQUIRE(code != NULL);
405 
406 	ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
407 
408 	bpfjit_free_code(code);
409 }
410 
411 ATF_TC(bpfjit_copx_ret_wirelen);
412 ATF_TC_HEAD(bpfjit_copx_ret_wirelen, tc)
413 {
414 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
415 	    "that returns the wirelen argument");
416 }
417 
418 ATF_TC_BODY(bpfjit_copx_ret_wirelen, tc)
419 {
420 	static struct bpf_insn insns[] = {
421 		BPF_STMT(BPF_LDX+BPF_IMM, 2), // retWL
422 		BPF_STMT(BPF_LD+BPF_IMM, 13),
423 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
424 		BPF_STMT(BPF_RET+BPF_A, 0)
425 	};
426 
427 	bpfjit_func_t code;
428 	uint8_t pkt[1] = { 0 };
429 	bpf_args_t args = {
430 		.pkt = pkt,
431 		.buflen = sizeof(pkt),
432 		.wirelen = sizeof(pkt)
433 	};
434 
435 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
436 
437 	code = bpfjit_generate_code(&ctx, insns, insn_count);
438 	ATF_REQUIRE(code != NULL);
439 
440 	ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
441 
442 	bpfjit_free_code(code);
443 }
444 
445 ATF_TC(bpfjit_copx_ret_nfuncs);
446 ATF_TC_HEAD(bpfjit_copx_ret_nfuncs, tc)
447 {
448 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
449 	    "that returns nfuncs member of the context argument");
450 }
451 
452 ATF_TC_BODY(bpfjit_copx_ret_nfuncs, tc)
453 {
454 	static struct bpf_insn insns[] = {
455 		BPF_STMT(BPF_LD+BPF_IMM, 13),
456 		BPF_STMT(BPF_LDX+BPF_IMM, 3), // retNF
457 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
458 		BPF_STMT(BPF_RET+BPF_A, 0)
459 	};
460 
461 	bpfjit_func_t code;
462 	uint8_t pkt[1] = { 0 };
463 	bpf_args_t args = {
464 		.pkt = pkt,
465 		.buflen = sizeof(pkt),
466 		.wirelen = sizeof(pkt)
467 	};
468 
469 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
470 
471 	code = bpfjit_generate_code(&ctx, insns, insn_count);
472 	ATF_REQUIRE(code != NULL);
473 
474 	ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
475 
476 	bpfjit_free_code(code);
477 }
478 
479 ATF_TC(bpfjit_copx_side_effect);
480 ATF_TC_HEAD(bpfjit_copx_side_effect, tc)
481 {
482 	atf_tc_set_md_var(tc, "descr",
483 	    "Test that ABC optimization doesn't skip BPF_COPX call");
484 }
485 
486 ATF_TC_BODY(bpfjit_copx_side_effect, tc)
487 {
488 	static struct bpf_insn insns[] = {
489 		BPF_STMT(BPF_LD+BPF_IMM, 13),
490 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
491 		BPF_STMT(BPF_LDX+BPF_IMM, 4), // setARG
492 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
493 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
494 		BPF_STMT(BPF_RET+BPF_A, 0)
495 	};
496 
497 	bpfjit_func_t code;
498 	bool arg = false;
499 	uint8_t pkt[1] = { 0 };
500 	bpf_args_t args = {
501 		.pkt = pkt,
502 		.buflen = sizeof(pkt),
503 		.wirelen = sizeof(pkt),
504 		.mem = NULL,
505 		.arg = &arg
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) == 0);
514 	ATF_CHECK(arg == true);
515 
516 	bpfjit_free_code(code);
517 }
518 
519 ATF_TC(bpfjit_copx_invalid_index);
520 ATF_TC_HEAD(bpfjit_copx_invalid_index, tc)
521 {
522 	atf_tc_set_md_var(tc, "descr",
523 	    "Test that out-of-range BPF_COPX call fails at runtime");
524 }
525 
526 ATF_TC_BODY(bpfjit_copx_invalid_index, tc)
527 {
528 	static struct bpf_insn insns[] = {
529 		BPF_STMT(BPF_LDX+BPF_IMM, 5), // invalid index
530 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
531 		BPF_STMT(BPF_RET+BPF_K, 27)
532 	};
533 
534 	bpfjit_func_t code;
535 	uint8_t pkt[1] = { 0 };
536 	bpf_args_t args = {
537 		.pkt = pkt,
538 		.buflen = sizeof(pkt),
539 		.wirelen = sizeof(pkt)
540 	};
541 
542 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
543 
544 	code = bpfjit_generate_code(&ctx, insns, insn_count);
545 	ATF_REQUIRE(code != NULL);
546 
547 	ATF_CHECK(code(&ctx, &args) == 0);
548 
549 	bpfjit_free_code(code);
550 }
551 
552 ATF_TP_ADD_TCS(tp)
553 {
554 
555 	ATF_TP_ADD_TC(tp, bpfjit_cop_no_ctx);
556 	ATF_TP_ADD_TC(tp, bpfjit_cop_ret_A);
557 	ATF_TP_ADD_TC(tp, bpfjit_cop_ret_buflen);
558 	ATF_TP_ADD_TC(tp, bpfjit_cop_ret_wirelen);
559 	ATF_TP_ADD_TC(tp, bpfjit_cop_ret_nfuncs);
560 	ATF_TP_ADD_TC(tp, bpfjit_cop_side_effect);
561 	ATF_TP_ADD_TC(tp, bpfjit_cop_invalid_index);
562 
563 	ATF_TP_ADD_TC(tp, bpfjit_copx_no_ctx);
564 	ATF_TP_ADD_TC(tp, bpfjit_copx_ret_A);
565 	ATF_TP_ADD_TC(tp, bpfjit_copx_ret_buflen);
566 	ATF_TP_ADD_TC(tp, bpfjit_copx_ret_wirelen);
567 	ATF_TP_ADD_TC(tp, bpfjit_copx_ret_nfuncs);
568 	ATF_TP_ADD_TC(tp, bpfjit_copx_side_effect);
569 	ATF_TP_ADD_TC(tp, bpfjit_copx_invalid_index);
570 
571 	return atf_no_error();
572 }
573