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