1/* 2 * Testsuite for eBPF verifier 3 * 4 * Copyright (c) 2014 PLUMgrid, http://plumgrid.com 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of version 2 of the GNU General Public 8 * License as published by the Free Software Foundation. 9 */ 10#include <stdio.h> 11#include <unistd.h> 12#include <linux/bpf.h> 13#include <errno.h> 14#include <linux/unistd.h> 15#include <string.h> 16#include <linux/filter.h> 17#include <stddef.h> 18#include "libbpf.h" 19 20#define MAX_INSNS 512 21#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) 22 23struct bpf_test { 24 const char *descr; 25 struct bpf_insn insns[MAX_INSNS]; 26 int fixup[32]; 27 const char *errstr; 28 enum { 29 ACCEPT, 30 REJECT 31 } result; 32}; 33 34static struct bpf_test tests[] = { 35 { 36 "add+sub+mul", 37 .insns = { 38 BPF_MOV64_IMM(BPF_REG_1, 1), 39 BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 2), 40 BPF_MOV64_IMM(BPF_REG_2, 3), 41 BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_2), 42 BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -1), 43 BPF_ALU64_IMM(BPF_MUL, BPF_REG_1, 3), 44 BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), 45 BPF_EXIT_INSN(), 46 }, 47 .result = ACCEPT, 48 }, 49 { 50 "unreachable", 51 .insns = { 52 BPF_EXIT_INSN(), 53 BPF_EXIT_INSN(), 54 }, 55 .errstr = "unreachable", 56 .result = REJECT, 57 }, 58 { 59 "unreachable2", 60 .insns = { 61 BPF_JMP_IMM(BPF_JA, 0, 0, 1), 62 BPF_JMP_IMM(BPF_JA, 0, 0, 0), 63 BPF_EXIT_INSN(), 64 }, 65 .errstr = "unreachable", 66 .result = REJECT, 67 }, 68 { 69 "out of range jump", 70 .insns = { 71 BPF_JMP_IMM(BPF_JA, 0, 0, 1), 72 BPF_EXIT_INSN(), 73 }, 74 .errstr = "jump out of range", 75 .result = REJECT, 76 }, 77 { 78 "out of range jump2", 79 .insns = { 80 BPF_JMP_IMM(BPF_JA, 0, 0, -2), 81 BPF_EXIT_INSN(), 82 }, 83 .errstr = "jump out of range", 84 .result = REJECT, 85 }, 86 { 87 "test1 ld_imm64", 88 .insns = { 89 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), 90 BPF_LD_IMM64(BPF_REG_0, 0), 91 BPF_LD_IMM64(BPF_REG_0, 0), 92 BPF_LD_IMM64(BPF_REG_0, 1), 93 BPF_LD_IMM64(BPF_REG_0, 1), 94 BPF_MOV64_IMM(BPF_REG_0, 2), 95 BPF_EXIT_INSN(), 96 }, 97 .errstr = "invalid BPF_LD_IMM insn", 98 .result = REJECT, 99 }, 100 { 101 "test2 ld_imm64", 102 .insns = { 103 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), 104 BPF_LD_IMM64(BPF_REG_0, 0), 105 BPF_LD_IMM64(BPF_REG_0, 0), 106 BPF_LD_IMM64(BPF_REG_0, 1), 107 BPF_LD_IMM64(BPF_REG_0, 1), 108 BPF_EXIT_INSN(), 109 }, 110 .errstr = "invalid BPF_LD_IMM insn", 111 .result = REJECT, 112 }, 113 { 114 "test3 ld_imm64", 115 .insns = { 116 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), 117 BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 0), 118 BPF_LD_IMM64(BPF_REG_0, 0), 119 BPF_LD_IMM64(BPF_REG_0, 0), 120 BPF_LD_IMM64(BPF_REG_0, 1), 121 BPF_LD_IMM64(BPF_REG_0, 1), 122 BPF_EXIT_INSN(), 123 }, 124 .errstr = "invalid bpf_ld_imm64 insn", 125 .result = REJECT, 126 }, 127 { 128 "test4 ld_imm64", 129 .insns = { 130 BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 0), 131 BPF_EXIT_INSN(), 132 }, 133 .errstr = "invalid bpf_ld_imm64 insn", 134 .result = REJECT, 135 }, 136 { 137 "test5 ld_imm64", 138 .insns = { 139 BPF_RAW_INSN(BPF_LD | BPF_IMM | BPF_DW, 0, 0, 0, 0), 140 }, 141 .errstr = "invalid bpf_ld_imm64 insn", 142 .result = REJECT, 143 }, 144 { 145 "no bpf_exit", 146 .insns = { 147 BPF_ALU64_REG(BPF_MOV, BPF_REG_0, BPF_REG_2), 148 }, 149 .errstr = "jump out of range", 150 .result = REJECT, 151 }, 152 { 153 "loop (back-edge)", 154 .insns = { 155 BPF_JMP_IMM(BPF_JA, 0, 0, -1), 156 BPF_EXIT_INSN(), 157 }, 158 .errstr = "back-edge", 159 .result = REJECT, 160 }, 161 { 162 "loop2 (back-edge)", 163 .insns = { 164 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), 165 BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), 166 BPF_MOV64_REG(BPF_REG_3, BPF_REG_0), 167 BPF_JMP_IMM(BPF_JA, 0, 0, -4), 168 BPF_EXIT_INSN(), 169 }, 170 .errstr = "back-edge", 171 .result = REJECT, 172 }, 173 { 174 "conditional loop", 175 .insns = { 176 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), 177 BPF_MOV64_REG(BPF_REG_2, BPF_REG_0), 178 BPF_MOV64_REG(BPF_REG_3, BPF_REG_0), 179 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, -3), 180 BPF_EXIT_INSN(), 181 }, 182 .errstr = "back-edge", 183 .result = REJECT, 184 }, 185 { 186 "read uninitialized register", 187 .insns = { 188 BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), 189 BPF_EXIT_INSN(), 190 }, 191 .errstr = "R2 !read_ok", 192 .result = REJECT, 193 }, 194 { 195 "read invalid register", 196 .insns = { 197 BPF_MOV64_REG(BPF_REG_0, -1), 198 BPF_EXIT_INSN(), 199 }, 200 .errstr = "R15 is invalid", 201 .result = REJECT, 202 }, 203 { 204 "program doesn't init R0 before exit", 205 .insns = { 206 BPF_ALU64_REG(BPF_MOV, BPF_REG_2, BPF_REG_1), 207 BPF_EXIT_INSN(), 208 }, 209 .errstr = "R0 !read_ok", 210 .result = REJECT, 211 }, 212 { 213 "program doesn't init R0 before exit in all branches", 214 .insns = { 215 BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), 216 BPF_MOV64_IMM(BPF_REG_0, 1), 217 BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 2), 218 BPF_EXIT_INSN(), 219 }, 220 .errstr = "R0 !read_ok", 221 .result = REJECT, 222 }, 223 { 224 "stack out of bounds", 225 .insns = { 226 BPF_ST_MEM(BPF_DW, BPF_REG_10, 8, 0), 227 BPF_EXIT_INSN(), 228 }, 229 .errstr = "invalid stack", 230 .result = REJECT, 231 }, 232 { 233 "invalid call insn1", 234 .insns = { 235 BPF_RAW_INSN(BPF_JMP | BPF_CALL | BPF_X, 0, 0, 0, 0), 236 BPF_EXIT_INSN(), 237 }, 238 .errstr = "BPF_CALL uses reserved", 239 .result = REJECT, 240 }, 241 { 242 "invalid call insn2", 243 .insns = { 244 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 1, 0), 245 BPF_EXIT_INSN(), 246 }, 247 .errstr = "BPF_CALL uses reserved", 248 .result = REJECT, 249 }, 250 { 251 "invalid function call", 252 .insns = { 253 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 1234567), 254 BPF_EXIT_INSN(), 255 }, 256 .errstr = "invalid func 1234567", 257 .result = REJECT, 258 }, 259 { 260 "uninitialized stack1", 261 .insns = { 262 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 263 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 264 BPF_LD_MAP_FD(BPF_REG_1, 0), 265 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), 266 BPF_EXIT_INSN(), 267 }, 268 .fixup = {2}, 269 .errstr = "invalid indirect read from stack", 270 .result = REJECT, 271 }, 272 { 273 "uninitialized stack2", 274 .insns = { 275 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 276 BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, -8), 277 BPF_EXIT_INSN(), 278 }, 279 .errstr = "invalid read from stack", 280 .result = REJECT, 281 }, 282 { 283 "check valid spill/fill", 284 .insns = { 285 /* spill R1(ctx) into stack */ 286 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8), 287 288 /* fill it back into R2 */ 289 BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -8), 290 291 /* should be able to access R0 = *(R2 + 8) */ 292 /* BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 8), */ 293 BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), 294 BPF_EXIT_INSN(), 295 }, 296 .result = ACCEPT, 297 }, 298 { 299 "check corrupted spill/fill", 300 .insns = { 301 /* spill R1(ctx) into stack */ 302 BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_1, -8), 303 304 /* mess up with R1 pointer on stack */ 305 BPF_ST_MEM(BPF_B, BPF_REG_10, -7, 0x23), 306 307 /* fill back into R0 should fail */ 308 BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), 309 310 BPF_EXIT_INSN(), 311 }, 312 .errstr = "corrupted spill", 313 .result = REJECT, 314 }, 315 { 316 "invalid src register in STX", 317 .insns = { 318 BPF_STX_MEM(BPF_B, BPF_REG_10, -1, -1), 319 BPF_EXIT_INSN(), 320 }, 321 .errstr = "R15 is invalid", 322 .result = REJECT, 323 }, 324 { 325 "invalid dst register in STX", 326 .insns = { 327 BPF_STX_MEM(BPF_B, 14, BPF_REG_10, -1), 328 BPF_EXIT_INSN(), 329 }, 330 .errstr = "R14 is invalid", 331 .result = REJECT, 332 }, 333 { 334 "invalid dst register in ST", 335 .insns = { 336 BPF_ST_MEM(BPF_B, 14, -1, -1), 337 BPF_EXIT_INSN(), 338 }, 339 .errstr = "R14 is invalid", 340 .result = REJECT, 341 }, 342 { 343 "invalid src register in LDX", 344 .insns = { 345 BPF_LDX_MEM(BPF_B, BPF_REG_0, 12, 0), 346 BPF_EXIT_INSN(), 347 }, 348 .errstr = "R12 is invalid", 349 .result = REJECT, 350 }, 351 { 352 "invalid dst register in LDX", 353 .insns = { 354 BPF_LDX_MEM(BPF_B, 11, BPF_REG_1, 0), 355 BPF_EXIT_INSN(), 356 }, 357 .errstr = "R11 is invalid", 358 .result = REJECT, 359 }, 360 { 361 "junk insn", 362 .insns = { 363 BPF_RAW_INSN(0, 0, 0, 0, 0), 364 BPF_EXIT_INSN(), 365 }, 366 .errstr = "invalid BPF_LD_IMM", 367 .result = REJECT, 368 }, 369 { 370 "junk insn2", 371 .insns = { 372 BPF_RAW_INSN(1, 0, 0, 0, 0), 373 BPF_EXIT_INSN(), 374 }, 375 .errstr = "BPF_LDX uses reserved fields", 376 .result = REJECT, 377 }, 378 { 379 "junk insn3", 380 .insns = { 381 BPF_RAW_INSN(-1, 0, 0, 0, 0), 382 BPF_EXIT_INSN(), 383 }, 384 .errstr = "invalid BPF_ALU opcode f0", 385 .result = REJECT, 386 }, 387 { 388 "junk insn4", 389 .insns = { 390 BPF_RAW_INSN(-1, -1, -1, -1, -1), 391 BPF_EXIT_INSN(), 392 }, 393 .errstr = "invalid BPF_ALU opcode f0", 394 .result = REJECT, 395 }, 396 { 397 "junk insn5", 398 .insns = { 399 BPF_RAW_INSN(0x7f, -1, -1, -1, -1), 400 BPF_EXIT_INSN(), 401 }, 402 .errstr = "BPF_ALU uses reserved fields", 403 .result = REJECT, 404 }, 405 { 406 "misaligned read from stack", 407 .insns = { 408 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 409 BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, -4), 410 BPF_EXIT_INSN(), 411 }, 412 .errstr = "misaligned access", 413 .result = REJECT, 414 }, 415 { 416 "invalid map_fd for function call", 417 .insns = { 418 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 419 BPF_ALU64_REG(BPF_MOV, BPF_REG_2, BPF_REG_10), 420 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 421 BPF_LD_MAP_FD(BPF_REG_1, 0), 422 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_delete_elem), 423 BPF_EXIT_INSN(), 424 }, 425 .errstr = "fd 0 is not pointing to valid bpf_map", 426 .result = REJECT, 427 }, 428 { 429 "don't check return value before access", 430 .insns = { 431 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 432 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 433 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 434 BPF_LD_MAP_FD(BPF_REG_1, 0), 435 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), 436 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), 437 BPF_EXIT_INSN(), 438 }, 439 .fixup = {3}, 440 .errstr = "R0 invalid mem access 'map_value_or_null'", 441 .result = REJECT, 442 }, 443 { 444 "access memory with incorrect alignment", 445 .insns = { 446 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 447 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 448 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 449 BPF_LD_MAP_FD(BPF_REG_1, 0), 450 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), 451 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1), 452 BPF_ST_MEM(BPF_DW, BPF_REG_0, 4, 0), 453 BPF_EXIT_INSN(), 454 }, 455 .fixup = {3}, 456 .errstr = "misaligned access", 457 .result = REJECT, 458 }, 459 { 460 "sometimes access memory with incorrect alignment", 461 .insns = { 462 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 463 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 464 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 465 BPF_LD_MAP_FD(BPF_REG_1, 0), 466 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), 467 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), 468 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 0), 469 BPF_EXIT_INSN(), 470 BPF_ST_MEM(BPF_DW, BPF_REG_0, 0, 1), 471 BPF_EXIT_INSN(), 472 }, 473 .fixup = {3}, 474 .errstr = "R0 invalid mem access", 475 .result = REJECT, 476 }, 477 { 478 "jump test 1", 479 .insns = { 480 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 481 BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, -8), 482 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 1), 483 BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 0), 484 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 1, 1), 485 BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 1), 486 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 2, 1), 487 BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 2), 488 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 3, 1), 489 BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 3), 490 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 4, 1), 491 BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 4), 492 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 5, 1), 493 BPF_ST_MEM(BPF_DW, BPF_REG_2, -32, 5), 494 BPF_MOV64_IMM(BPF_REG_0, 0), 495 BPF_EXIT_INSN(), 496 }, 497 .result = ACCEPT, 498 }, 499 { 500 "jump test 2", 501 .insns = { 502 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 503 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 2), 504 BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 0), 505 BPF_JMP_IMM(BPF_JA, 0, 0, 14), 506 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 1, 2), 507 BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 0), 508 BPF_JMP_IMM(BPF_JA, 0, 0, 11), 509 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 2, 2), 510 BPF_ST_MEM(BPF_DW, BPF_REG_2, -32, 0), 511 BPF_JMP_IMM(BPF_JA, 0, 0, 8), 512 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 3, 2), 513 BPF_ST_MEM(BPF_DW, BPF_REG_2, -40, 0), 514 BPF_JMP_IMM(BPF_JA, 0, 0, 5), 515 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 4, 2), 516 BPF_ST_MEM(BPF_DW, BPF_REG_2, -48, 0), 517 BPF_JMP_IMM(BPF_JA, 0, 0, 2), 518 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 5, 1), 519 BPF_ST_MEM(BPF_DW, BPF_REG_2, -56, 0), 520 BPF_MOV64_IMM(BPF_REG_0, 0), 521 BPF_EXIT_INSN(), 522 }, 523 .result = ACCEPT, 524 }, 525 { 526 "jump test 3", 527 .insns = { 528 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 529 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 3), 530 BPF_ST_MEM(BPF_DW, BPF_REG_2, -8, 0), 531 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 532 BPF_JMP_IMM(BPF_JA, 0, 0, 19), 533 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 1, 3), 534 BPF_ST_MEM(BPF_DW, BPF_REG_2, -16, 0), 535 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -16), 536 BPF_JMP_IMM(BPF_JA, 0, 0, 15), 537 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 2, 3), 538 BPF_ST_MEM(BPF_DW, BPF_REG_2, -32, 0), 539 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -32), 540 BPF_JMP_IMM(BPF_JA, 0, 0, 11), 541 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 3, 3), 542 BPF_ST_MEM(BPF_DW, BPF_REG_2, -40, 0), 543 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -40), 544 BPF_JMP_IMM(BPF_JA, 0, 0, 7), 545 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 4, 3), 546 BPF_ST_MEM(BPF_DW, BPF_REG_2, -48, 0), 547 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -48), 548 BPF_JMP_IMM(BPF_JA, 0, 0, 3), 549 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 5, 0), 550 BPF_ST_MEM(BPF_DW, BPF_REG_2, -56, 0), 551 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -56), 552 BPF_LD_MAP_FD(BPF_REG_1, 0), 553 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_delete_elem), 554 BPF_EXIT_INSN(), 555 }, 556 .fixup = {24}, 557 .result = ACCEPT, 558 }, 559 { 560 "jump test 4", 561 .insns = { 562 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), 563 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), 564 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), 565 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), 566 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), 567 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), 568 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), 569 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), 570 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), 571 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), 572 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), 573 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), 574 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), 575 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), 576 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), 577 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), 578 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), 579 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), 580 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), 581 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), 582 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), 583 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), 584 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), 585 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), 586 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), 587 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), 588 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), 589 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), 590 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), 591 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), 592 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), 593 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), 594 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 1), 595 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 2), 596 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 3), 597 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 4), 598 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0), 599 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0), 600 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0), 601 BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, BPF_REG_10, 0), 602 BPF_MOV64_IMM(BPF_REG_0, 0), 603 BPF_EXIT_INSN(), 604 }, 605 .result = ACCEPT, 606 }, 607 { 608 "jump test 5", 609 .insns = { 610 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 611 BPF_MOV64_REG(BPF_REG_3, BPF_REG_2), 612 BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), 613 BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8), 614 BPF_JMP_IMM(BPF_JA, 0, 0, 2), 615 BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8), 616 BPF_JMP_IMM(BPF_JA, 0, 0, 0), 617 BPF_MOV64_IMM(BPF_REG_0, 0), 618 BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), 619 BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8), 620 BPF_JMP_IMM(BPF_JA, 0, 0, 2), 621 BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8), 622 BPF_JMP_IMM(BPF_JA, 0, 0, 0), 623 BPF_MOV64_IMM(BPF_REG_0, 0), 624 BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), 625 BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8), 626 BPF_JMP_IMM(BPF_JA, 0, 0, 2), 627 BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8), 628 BPF_JMP_IMM(BPF_JA, 0, 0, 0), 629 BPF_MOV64_IMM(BPF_REG_0, 0), 630 BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), 631 BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8), 632 BPF_JMP_IMM(BPF_JA, 0, 0, 2), 633 BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8), 634 BPF_JMP_IMM(BPF_JA, 0, 0, 0), 635 BPF_MOV64_IMM(BPF_REG_0, 0), 636 BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), 637 BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, -8), 638 BPF_JMP_IMM(BPF_JA, 0, 0, 2), 639 BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_2, -8), 640 BPF_JMP_IMM(BPF_JA, 0, 0, 0), 641 BPF_MOV64_IMM(BPF_REG_0, 0), 642 BPF_EXIT_INSN(), 643 }, 644 .result = ACCEPT, 645 }, 646 { 647 "access skb fields ok", 648 .insns = { 649 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 650 offsetof(struct __sk_buff, len)), 651 BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1), 652 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 653 offsetof(struct __sk_buff, mark)), 654 BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1), 655 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 656 offsetof(struct __sk_buff, pkt_type)), 657 BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 1), 658 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 659 offsetof(struct __sk_buff, queue_mapping)), 660 BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0), 661 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 662 offsetof(struct __sk_buff, protocol)), 663 BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0), 664 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 665 offsetof(struct __sk_buff, vlan_present)), 666 BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0), 667 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 668 offsetof(struct __sk_buff, vlan_tci)), 669 BPF_JMP_IMM(BPF_JGE, BPF_REG_0, 0, 0), 670 BPF_EXIT_INSN(), 671 }, 672 .result = ACCEPT, 673 }, 674 { 675 "access skb fields bad1", 676 .insns = { 677 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, -4), 678 BPF_EXIT_INSN(), 679 }, 680 .errstr = "invalid bpf_context access", 681 .result = REJECT, 682 }, 683 { 684 "access skb fields bad2", 685 .insns = { 686 BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 9), 687 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 688 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 689 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 690 BPF_LD_MAP_FD(BPF_REG_1, 0), 691 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), 692 BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), 693 BPF_EXIT_INSN(), 694 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), 695 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 696 offsetof(struct __sk_buff, pkt_type)), 697 BPF_EXIT_INSN(), 698 }, 699 .fixup = {4}, 700 .errstr = "different pointers", 701 .result = REJECT, 702 }, 703 { 704 "access skb fields bad3", 705 .insns = { 706 BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 2), 707 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 708 offsetof(struct __sk_buff, pkt_type)), 709 BPF_EXIT_INSN(), 710 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 711 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 712 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 713 BPF_LD_MAP_FD(BPF_REG_1, 0), 714 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), 715 BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), 716 BPF_EXIT_INSN(), 717 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), 718 BPF_JMP_IMM(BPF_JA, 0, 0, -12), 719 }, 720 .fixup = {6}, 721 .errstr = "different pointers", 722 .result = REJECT, 723 }, 724 { 725 "access skb fields bad4", 726 .insns = { 727 BPF_JMP_IMM(BPF_JGE, BPF_REG_1, 0, 3), 728 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_1, 729 offsetof(struct __sk_buff, len)), 730 BPF_MOV64_IMM(BPF_REG_0, 0), 731 BPF_EXIT_INSN(), 732 BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), 733 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 734 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 735 BPF_LD_MAP_FD(BPF_REG_1, 0), 736 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), 737 BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), 738 BPF_EXIT_INSN(), 739 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), 740 BPF_JMP_IMM(BPF_JA, 0, 0, -13), 741 }, 742 .fixup = {7}, 743 .errstr = "different pointers", 744 .result = REJECT, 745 }, 746}; 747 748static int probe_filter_length(struct bpf_insn *fp) 749{ 750 int len = 0; 751 752 for (len = MAX_INSNS - 1; len > 0; --len) 753 if (fp[len].code != 0 || fp[len].imm != 0) 754 break; 755 756 return len + 1; 757} 758 759static int create_map(void) 760{ 761 long long key, value = 0; 762 int map_fd; 763 764 map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 1024); 765 if (map_fd < 0) { 766 printf("failed to create map '%s'\n", strerror(errno)); 767 } 768 769 return map_fd; 770} 771 772static int test(void) 773{ 774 int prog_fd, i, pass_cnt = 0, err_cnt = 0; 775 776 for (i = 0; i < ARRAY_SIZE(tests); i++) { 777 struct bpf_insn *prog = tests[i].insns; 778 int prog_len = probe_filter_length(prog); 779 int *fixup = tests[i].fixup; 780 int map_fd = -1; 781 782 if (*fixup) { 783 map_fd = create_map(); 784 785 do { 786 prog[*fixup].imm = map_fd; 787 fixup++; 788 } while (*fixup); 789 } 790 printf("#%d %s ", i, tests[i].descr); 791 792 prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog, 793 prog_len * sizeof(struct bpf_insn), 794 "GPL", 0); 795 796 if (tests[i].result == ACCEPT) { 797 if (prog_fd < 0) { 798 printf("FAIL\nfailed to load prog '%s'\n", 799 strerror(errno)); 800 printf("%s", bpf_log_buf); 801 err_cnt++; 802 goto fail; 803 } 804 } else { 805 if (prog_fd >= 0) { 806 printf("FAIL\nunexpected success to load\n"); 807 printf("%s", bpf_log_buf); 808 err_cnt++; 809 goto fail; 810 } 811 if (strstr(bpf_log_buf, tests[i].errstr) == 0) { 812 printf("FAIL\nunexpected error message: %s", 813 bpf_log_buf); 814 err_cnt++; 815 goto fail; 816 } 817 } 818 819 pass_cnt++; 820 printf("OK\n"); 821fail: 822 if (map_fd >= 0) 823 close(map_fd); 824 close(prog_fd); 825 826 } 827 printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, err_cnt); 828 829 return 0; 830} 831 832int main(void) 833{ 834 return test(); 835} 836