t_cop.c revision 1.2 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