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