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 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 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 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 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 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); 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 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); 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 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); 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 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); 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 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); 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 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); 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 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); 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 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); 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 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); 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 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); 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 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); 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 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); 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 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); 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 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); 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 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); 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 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); 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 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 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