1 /* $NetBSD: t_cop.c,v 1.3 2014/07/13 21:35:33 alnsn 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.3 2014/07/13 21:35:33 alnsn 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
retA(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)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
retBL(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)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
retWL(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)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
retNF(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)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
setARG(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)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);
ATF_TC_HEAD(bpfjit_cop_no_ctx,tc)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
ATF_TC_BODY(bpfjit_cop_no_ctx,tc)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);
ATF_TC_HEAD(bpfjit_cop_ret_A,tc)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
ATF_TC_BODY(bpfjit_cop_ret_A,tc)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);
ATF_TC_HEAD(bpfjit_cop_ret_buflen,tc)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
ATF_TC_BODY(bpfjit_cop_ret_buflen,tc)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);
ATF_TC_HEAD(bpfjit_cop_ret_wirelen,tc)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
ATF_TC_BODY(bpfjit_cop_ret_wirelen,tc)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);
ATF_TC_HEAD(bpfjit_cop_ret_nfuncs,tc)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
ATF_TC_BODY(bpfjit_cop_ret_nfuncs,tc)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);
ATF_TC_HEAD(bpfjit_cop_side_effect,tc)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
ATF_TC_BODY(bpfjit_cop_side_effect,tc)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);
ATF_TC_HEAD(bpfjit_cop_copx,tc)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
ATF_TC_BODY(bpfjit_cop_copx,tc)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);
ATF_TC_HEAD(bpfjit_cop_invalid_index,tc)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
ATF_TC_BODY(bpfjit_cop_invalid_index,tc)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);
ATF_TC_HEAD(bpfjit_copx_no_ctx,tc)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
ATF_TC_BODY(bpfjit_copx_no_ctx,tc)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);
ATF_TC_HEAD(bpfjit_copx_ret_A,tc)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
ATF_TC_BODY(bpfjit_copx_ret_A,tc)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);
ATF_TC_HEAD(bpfjit_copx_ret_buflen,tc)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
ATF_TC_BODY(bpfjit_copx_ret_buflen,tc)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);
ATF_TC_HEAD(bpfjit_copx_ret_wirelen,tc)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
ATF_TC_BODY(bpfjit_copx_ret_wirelen,tc)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);
ATF_TC_HEAD(bpfjit_copx_ret_nfuncs,tc)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
ATF_TC_BODY(bpfjit_copx_ret_nfuncs,tc)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);
ATF_TC_HEAD(bpfjit_copx_side_effect,tc)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
ATF_TC_BODY(bpfjit_copx_side_effect,tc)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);
ATF_TC_HEAD(bpfjit_copx_cop,tc)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
ATF_TC_BODY(bpfjit_copx_cop,tc)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);
ATF_TC_HEAD(bpfjit_copx_invalid_index,tc)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
ATF_TC_BODY(bpfjit_copx_invalid_index,tc)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
ATF_TP_ADD_TCS(tp)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