1 /* $NetBSD: t_extmem.c,v 1.2 2017/01/13 21:30:42 christos 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_extmem.c,v 1.2 2017/01/13 21:30:42 christos 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 retM(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A); 52 53 static const bpf_copfunc_t copfuncs[] = { 54 &retM 55 }; 56 57 static const bpf_ctx_t ctx = { 58 .copfuncs = copfuncs, 59 .nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]), 60 .extwords = 4, 61 .preinited = BPF_MEMWORD_INIT(0) | BPF_MEMWORD_INIT(3), 62 }; 63 64 static uint32_t 65 retM(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A) 66 { 67 68 return args->mem[(uintptr_t)args->arg]; 69 } 70 71 72 ATF_TC(bpfjit_extmem_load_preinited); 73 ATF_TC_HEAD(bpfjit_extmem_load_preinited, tc) 74 { 75 atf_tc_set_md_var(tc, "descr", "Test a load of external " 76 "pre-initialized memory"); 77 } 78 79 ATF_TC_BODY(bpfjit_extmem_load_preinited, tc) 80 { 81 static struct bpf_insn insns[] = { 82 BPF_STMT(BPF_LD+BPF_MEM, 3), 83 BPF_STMT(BPF_RET+BPF_A, 0) 84 }; 85 86 bpfjit_func_t code; 87 uint8_t pkt[1] = { 0 }; 88 uint32_t mem[ctx.extwords]; 89 90 /* Pre-inited words. */ 91 mem[0] = 0; 92 mem[3] = 3; 93 94 bpf_args_t args = { 95 .pkt = pkt, 96 .buflen = sizeof(pkt), 97 .wirelen = sizeof(pkt), 98 .mem = mem, 99 }; 100 101 size_t insn_count = sizeof(insns) / sizeof(insns[0]); 102 103 RZ(rump_init()); 104 105 rump_schedule(); 106 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 107 rump_unschedule(); 108 ATF_REQUIRE(code != NULL); 109 110 ATF_CHECK(code(&ctx, &args) == 3); 111 112 rump_schedule(); 113 rumpns_bpfjit_free_code(code); 114 rump_unschedule(); 115 } 116 117 ATF_TC(bpfjit_extmem_invalid_load); 118 ATF_TC_HEAD(bpfjit_extmem_invalid_load, tc) 119 { 120 atf_tc_set_md_var(tc, "descr", "Test that out-of-range load " 121 "fails validation"); 122 } 123 124 ATF_TC_BODY(bpfjit_extmem_invalid_load, tc) 125 { 126 static struct bpf_insn insns[] = { 127 BPF_STMT(BPF_LD+BPF_MEM, 4), 128 BPF_STMT(BPF_RET+BPF_A, 0) 129 }; 130 131 bpfjit_func_t code; 132 size_t insn_count = sizeof(insns) / sizeof(insns[0]); 133 134 RZ(rump_init()); 135 136 rump_schedule(); 137 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 138 rump_unschedule(); 139 ATF_CHECK(code == NULL); 140 } 141 142 ATF_TC(bpfjit_extmem_store); 143 ATF_TC_HEAD(bpfjit_extmem_store, tc) 144 { 145 atf_tc_set_md_var(tc, "descr", "Test stores to external memory"); 146 } 147 148 ATF_TC_BODY(bpfjit_extmem_store, tc) 149 { 150 static struct bpf_insn insns[] = { 151 BPF_STMT(BPF_LD+BPF_IMM, 1), /* A <- 1 */ 152 BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2), /* X <- 2 */ 153 BPF_STMT(BPF_ST, 1), /* M[1] <- A */ 154 BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */ 155 BPF_STMT(BPF_STX, 2), /* M[2] <- X */ 156 BPF_STMT(BPF_ST, 3), /* M[3] <- A */ 157 BPF_STMT(BPF_RET+BPF_A, 0) /* ret A */ 158 }; 159 160 bpfjit_func_t code; 161 uint8_t pkt[1] = { 0 }; 162 uint32_t mem[ctx.extwords]; 163 164 /* Pre-inited words. */ 165 mem[0] = 0; 166 mem[3] = 7; 167 168 mem[1] = mem[2] = 0xdeadbeef; 169 170 bpf_args_t args = { 171 .pkt = pkt, 172 .buflen = sizeof(pkt), 173 .wirelen = sizeof(pkt), 174 .mem = mem, 175 }; 176 177 size_t insn_count = sizeof(insns) / sizeof(insns[0]); 178 179 RZ(rump_init()); 180 181 rump_schedule(); 182 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 183 rump_unschedule(); 184 ATF_REQUIRE(code != NULL); 185 186 ATF_CHECK(code(&ctx, &args) == 3); 187 188 rump_schedule(); 189 rumpns_bpfjit_free_code(code); 190 rump_unschedule(); 191 192 ATF_CHECK(mem[0] == 0); 193 ATF_CHECK(mem[1] == 1); 194 ATF_CHECK(mem[2] == 2); 195 ATF_CHECK(mem[3] == 3); 196 } 197 198 ATF_TC(bpfjit_extmem_side_effect); 199 ATF_TC_HEAD(bpfjit_extmem_side_effect, tc) 200 { 201 atf_tc_set_md_var(tc, "descr", "Test that ABC optimization doesn\'t " 202 "skip stores to external memory"); 203 } 204 205 ATF_TC_BODY(bpfjit_extmem_side_effect, tc) 206 { 207 static struct bpf_insn insns[] = { 208 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A <- P[0] */ 209 BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2), /* X <- 2 */ 210 BPF_STMT(BPF_ST, 1), /* M[1] <- A */ 211 BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */ 212 BPF_STMT(BPF_STX, 2), /* M[2] <- X */ 213 BPF_STMT(BPF_ST, 3), /* M[3] <- A */ 214 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99), /* A <- P[99] */ 215 BPF_STMT(BPF_RET+BPF_A, 0) /* ret A */ 216 }; 217 218 bpfjit_func_t code; 219 uint8_t pkt[1] = { 1 }; 220 uint32_t mem[ctx.extwords]; 221 222 /* Pre-inited words. */ 223 mem[0] = 0; 224 mem[3] = 7; 225 226 mem[1] = mem[2] = 0xdeadbeef; 227 228 bpf_args_t args = { 229 .pkt = pkt, 230 .buflen = sizeof(pkt), 231 .wirelen = sizeof(pkt), 232 .mem = mem, 233 }; 234 235 size_t insn_count = sizeof(insns) / sizeof(insns[0]); 236 237 RZ(rump_init()); 238 239 rump_schedule(); 240 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 241 rump_unschedule(); 242 ATF_REQUIRE(code != NULL); 243 244 ATF_CHECK(code(&ctx, &args) == 0); 245 246 rump_schedule(); 247 rumpns_bpfjit_free_code(code); 248 rump_unschedule(); 249 250 ATF_CHECK(mem[0] == 0); 251 ATF_CHECK(mem[1] == 1); 252 ATF_CHECK(mem[2] == 2); 253 ATF_CHECK(mem[3] == 3); 254 } 255 256 ATF_TC(bpfjit_extmem_invalid_store); 257 ATF_TC_HEAD(bpfjit_extmem_invalid_store, tc) 258 { 259 atf_tc_set_md_var(tc, "descr", "Test that out-of-range store " 260 "fails validation"); 261 } 262 263 ATF_TC_BODY(bpfjit_extmem_invalid_store, tc) 264 { 265 static struct bpf_insn insns[] = { 266 BPF_STMT(BPF_ST, 4), 267 BPF_STMT(BPF_RET+BPF_A, 0) 268 }; 269 270 bpfjit_func_t code; 271 size_t insn_count = sizeof(insns) / sizeof(insns[0]); 272 273 RZ(rump_init()); 274 275 rump_schedule(); 276 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 277 rump_unschedule(); 278 ATF_CHECK(code == NULL); 279 } 280 281 ATF_TC(bpfjit_cop_ret_mem); 282 ATF_TC_HEAD(bpfjit_cop_ret_mem, tc) 283 { 284 atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 285 "that returns a content of external memory word"); 286 } 287 288 ATF_TC_BODY(bpfjit_cop_ret_mem, tc) 289 { 290 static struct bpf_insn insns[] = { 291 BPF_STMT(BPF_LD+BPF_IMM, 13), 292 BPF_STMT(BPF_ST, 2), 293 BPF_STMT(BPF_LD+BPF_IMM, 137), 294 BPF_STMT(BPF_ST, 1), 295 BPF_STMT(BPF_MISC+BPF_COP, 0), // retM 296 BPF_STMT(BPF_RET+BPF_A, 0) 297 }; 298 299 bpfjit_func_t code; 300 uint8_t pkt[1] = { 0 }; 301 uint32_t mem[ctx.extwords]; 302 void *arg = (void*)(uintptr_t)2; 303 304 /* Pre-inited words. */ 305 mem[0] = 0; 306 mem[3] = 3; 307 308 bpf_args_t args = { 309 .pkt = pkt, 310 .buflen = sizeof(pkt), 311 .wirelen = sizeof(pkt), 312 .arg = arg, 313 .mem = mem, 314 }; 315 316 size_t insn_count = sizeof(insns) / sizeof(insns[0]); 317 318 RZ(rump_init()); 319 320 rump_schedule(); 321 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 322 rump_unschedule(); 323 ATF_REQUIRE(code != NULL); 324 325 ATF_CHECK(code(&ctx, &args) == 13); 326 327 rump_schedule(); 328 rumpns_bpfjit_free_code(code); 329 rump_unschedule(); 330 } 331 332 ATF_TC(bpfjit_cop_ret_preinited_mem); 333 ATF_TC_HEAD(bpfjit_cop_ret_preinited_mem, tc) 334 { 335 atf_tc_set_md_var(tc, "descr", "Test coprocessor function that " 336 "returns a content of external pre-initialized memory word"); 337 } 338 339 ATF_TC_BODY(bpfjit_cop_ret_preinited_mem, tc) 340 { 341 static struct bpf_insn insns[] = { 342 BPF_STMT(BPF_LD+BPF_IMM, 13), 343 BPF_STMT(BPF_ST, 2), 344 BPF_STMT(BPF_LD+BPF_IMM, 137), 345 BPF_STMT(BPF_ST, 1), 346 BPF_STMT(BPF_MISC+BPF_COP, 0), // retM 347 BPF_STMT(BPF_RET+BPF_A, 0) 348 }; 349 350 bpfjit_func_t code; 351 uint8_t pkt[1] = { 0 }; 352 uint32_t mem[ctx.extwords]; 353 void *arg = (void*)(uintptr_t)3; 354 355 /* Pre-inited words. */ 356 mem[0] = 0; 357 mem[3] = 3; 358 359 bpf_args_t args = { 360 .pkt = pkt, 361 .buflen = sizeof(pkt), 362 .wirelen = sizeof(pkt), 363 .arg = arg, 364 .mem = mem, 365 }; 366 367 size_t insn_count = sizeof(insns) / sizeof(insns[0]); 368 369 RZ(rump_init()); 370 371 rump_schedule(); 372 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 373 rump_unschedule(); 374 ATF_REQUIRE(code != NULL); 375 376 ATF_CHECK(code(&ctx, &args) == 3); 377 378 rump_schedule(); 379 rumpns_bpfjit_free_code(code); 380 rump_unschedule(); 381 } 382 383 ATF_TC(bpfjit_copx_ret_mem); 384 ATF_TC_HEAD(bpfjit_copx_ret_mem, tc) 385 { 386 atf_tc_set_md_var(tc, "descr", "Test coprocessor function " 387 "that returns a content of external memory word"); 388 } 389 390 ATF_TC_BODY(bpfjit_copx_ret_mem, tc) 391 { 392 static struct bpf_insn insns[] = { 393 BPF_STMT(BPF_LD+BPF_IMM, 13), 394 BPF_STMT(BPF_ST, 2), 395 BPF_STMT(BPF_LD+BPF_IMM, 137), 396 BPF_STMT(BPF_ST, 1), 397 BPF_STMT(BPF_LDX+BPF_IMM, 0), // retM 398 BPF_STMT(BPF_MISC+BPF_COPX, 0), 399 BPF_STMT(BPF_RET+BPF_A, 0) 400 }; 401 402 bpfjit_func_t code; 403 uint8_t pkt[1] = { 0 }; 404 uint32_t mem[ctx.extwords]; 405 void *arg = (void*)(uintptr_t)2; 406 407 /* Pre-inited words. */ 408 mem[0] = 0; 409 mem[3] = 3; 410 411 bpf_args_t args = { 412 .pkt = pkt, 413 .buflen = sizeof(pkt), 414 .wirelen = sizeof(pkt), 415 .arg = arg, 416 .mem = mem, 417 }; 418 419 size_t insn_count = sizeof(insns) / sizeof(insns[0]); 420 421 RZ(rump_init()); 422 423 rump_schedule(); 424 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 425 rump_unschedule(); 426 ATF_REQUIRE(code != NULL); 427 428 ATF_CHECK(code(&ctx, &args) == 13); 429 430 rump_schedule(); 431 rumpns_bpfjit_free_code(code); 432 rump_unschedule(); 433 } 434 435 ATF_TC(bpfjit_copx_ret_preinited_mem); 436 ATF_TC_HEAD(bpfjit_copx_ret_preinited_mem, tc) 437 { 438 atf_tc_set_md_var(tc, "descr", "Test coprocessor function that " 439 "returns a content of external pre-initialized memory word"); 440 } 441 442 ATF_TC_BODY(bpfjit_copx_ret_preinited_mem, tc) 443 { 444 static struct bpf_insn insns[] = { 445 BPF_STMT(BPF_LD+BPF_IMM, 13), 446 BPF_STMT(BPF_ST, 2), 447 BPF_STMT(BPF_LD+BPF_IMM, 137), 448 BPF_STMT(BPF_ST, 1), 449 BPF_STMT(BPF_LDX+BPF_IMM, 0), // retM 450 BPF_STMT(BPF_MISC+BPF_COPX, 0), 451 BPF_STMT(BPF_RET+BPF_A, 0) 452 }; 453 454 bpfjit_func_t code; 455 uint8_t pkt[1] = { 0 }; 456 uint32_t mem[ctx.extwords]; 457 void *arg = (void*)(uintptr_t)3; 458 459 /* Pre-inited words. */ 460 mem[0] = 0; 461 mem[3] = 3; 462 463 bpf_args_t args = { 464 .pkt = pkt, 465 .buflen = sizeof(pkt), 466 .wirelen = sizeof(pkt), 467 .arg = arg, 468 .mem = mem, 469 }; 470 471 size_t insn_count = sizeof(insns) / sizeof(insns[0]); 472 473 RZ(rump_init()); 474 475 rump_schedule(); 476 code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count); 477 rump_unschedule(); 478 ATF_REQUIRE(code != NULL); 479 480 ATF_CHECK(code(&ctx, &args) == 3); 481 482 rump_schedule(); 483 rumpns_bpfjit_free_code(code); 484 rump_unschedule(); 485 } 486 487 ATF_TP_ADD_TCS(tp) 488 { 489 490 /* 491 * For every new test please also add a similar test 492 * to ../../lib/libbpfjit/t_extmem.c 493 */ 494 //ATF_TP_ADD_TC(tp, bpfjit_extmem_load_default); 495 ATF_TP_ADD_TC(tp, bpfjit_extmem_load_preinited); 496 ATF_TP_ADD_TC(tp, bpfjit_extmem_invalid_load); 497 ATF_TP_ADD_TC(tp, bpfjit_extmem_store); 498 ATF_TP_ADD_TC(tp, bpfjit_extmem_side_effect); 499 ATF_TP_ADD_TC(tp, bpfjit_extmem_invalid_store); 500 ATF_TP_ADD_TC(tp, bpfjit_cop_ret_mem); 501 ATF_TP_ADD_TC(tp, bpfjit_cop_ret_preinited_mem); 502 ATF_TP_ADD_TC(tp, bpfjit_copx_ret_mem); 503 ATF_TP_ADD_TC(tp, bpfjit_copx_ret_preinited_mem); 504 505 return atf_no_error(); 506 } 507