Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: add tests for subtraction & negative numbers

Signed-off-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Edward Cree and committed by
David S. Miller
f999d64c 1f9ab38f

+104
+104
tools/testing/selftests/bpf/test_align.c
··· 497 497 {16, "R6=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, 498 498 } 499 499 }, 500 + { 501 + .descr = "variable subtraction", 502 + .insns = { 503 + /* Create an unknown offset, (4n+2)-aligned */ 504 + LOAD_UNKNOWN(BPF_REG_6), 505 + BPF_MOV64_REG(BPF_REG_7, BPF_REG_6), 506 + BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2), 507 + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 14), 508 + /* Create another unknown, (4n)-aligned, and subtract 509 + * it from the first one 510 + */ 511 + BPF_ALU64_IMM(BPF_LSH, BPF_REG_7, 2), 512 + BPF_ALU64_REG(BPF_SUB, BPF_REG_6, BPF_REG_7), 513 + /* Bounds-check the result */ 514 + BPF_JMP_IMM(BPF_JSGE, BPF_REG_6, 0, 1), 515 + BPF_EXIT_INSN(), 516 + /* Add it to the packet pointer */ 517 + BPF_MOV64_REG(BPF_REG_5, BPF_REG_2), 518 + BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6), 519 + /* Check bounds and perform a read */ 520 + BPF_MOV64_REG(BPF_REG_4, BPF_REG_5), 521 + BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4), 522 + BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1), 523 + BPF_EXIT_INSN(), 524 + BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_5, 0), 525 + BPF_EXIT_INSN(), 526 + }, 527 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 528 + .matches = { 529 + /* Calculated offset in R6 has unknown value, but known 530 + * alignment of 4. 531 + */ 532 + {7, "R2=pkt(id=0,off=0,r=8,imm=0)"}, 533 + {9, "R6=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, 534 + /* Adding 14 makes R6 be (4n+2) */ 535 + {10, "R6=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"}, 536 + /* New unknown value in R7 is (4n) */ 537 + {11, "R7=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"}, 538 + /* Subtracting it from R6 blows our unsigned bounds */ 539 + {12, "R6=inv(id=0,smin_value=-1006,smax_value=1034,var_off=(0x2; 0xfffffffffffffffc))"}, 540 + /* Checked s>= 0 */ 541 + {14, "R6=inv(id=0,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc))"}, 542 + /* At the time the word size load is performed from R5, 543 + * its total fixed offset is NET_IP_ALIGN + reg->off (0) 544 + * which is 2. Then the variable offset is (4n+2), so 545 + * the total offset is 4-byte aligned and meets the 546 + * load's requirements. 547 + */ 548 + {20, "R5=pkt(id=1,off=0,r=4,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc))"}, 549 + }, 550 + }, 551 + { 552 + .descr = "pointer variable subtraction", 553 + .insns = { 554 + /* Create an unknown offset, (4n+2)-aligned and bounded 555 + * to [14,74] 556 + */ 557 + LOAD_UNKNOWN(BPF_REG_6), 558 + BPF_MOV64_REG(BPF_REG_7, BPF_REG_6), 559 + BPF_ALU64_IMM(BPF_AND, BPF_REG_6, 0xf), 560 + BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2), 561 + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 14), 562 + /* Subtract it from the packet pointer */ 563 + BPF_MOV64_REG(BPF_REG_5, BPF_REG_2), 564 + BPF_ALU64_REG(BPF_SUB, BPF_REG_5, BPF_REG_6), 565 + /* Create another unknown, (4n)-aligned and >= 74. 566 + * That in fact means >= 76, since 74 % 4 == 2 567 + */ 568 + BPF_ALU64_IMM(BPF_LSH, BPF_REG_7, 2), 569 + BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, 76), 570 + /* Add it to the packet pointer */ 571 + BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_7), 572 + /* Check bounds and perform a read */ 573 + BPF_MOV64_REG(BPF_REG_4, BPF_REG_5), 574 + BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4), 575 + BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1), 576 + BPF_EXIT_INSN(), 577 + BPF_LDX_MEM(BPF_W, BPF_REG_6, BPF_REG_5, 0), 578 + BPF_EXIT_INSN(), 579 + }, 580 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 581 + .matches = { 582 + /* Calculated offset in R6 has unknown value, but known 583 + * alignment of 4. 584 + */ 585 + {7, "R2=pkt(id=0,off=0,r=8,imm=0)"}, 586 + {10, "R6=inv(id=0,umax_value=60,var_off=(0x0; 0x3c))"}, 587 + /* Adding 14 makes R6 be (4n+2) */ 588 + {11, "R6=inv(id=0,umin_value=14,umax_value=74,var_off=(0x2; 0x7c))"}, 589 + /* Subtracting from packet pointer overflows ubounds */ 590 + {13, "R5=pkt(id=1,off=0,r=8,umin_value=18446744073709551542,umax_value=18446744073709551602,var_off=(0xffffffffffffff82; 0x7c))"}, 591 + /* New unknown value in R7 is (4n), >= 76 */ 592 + {15, "R7=inv(id=0,umin_value=76,umax_value=1096,var_off=(0x0; 0x7fc))"}, 593 + /* Adding it to packet pointer gives nice bounds again */ 594 + {16, "R5=pkt(id=2,off=0,r=0,umin_value=2,umax_value=1082,var_off=(0x2; 0x7fc))"}, 595 + /* At the time the word size load is performed from R5, 596 + * its total fixed offset is NET_IP_ALIGN + reg->off (0) 597 + * which is 2. Then the variable offset is (4n+2), so 598 + * the total offset is 4-byte aligned and meets the 599 + * load's requirements. 600 + */ 601 + {20, "R5=pkt(id=2,off=0,r=4,umin_value=2,umax_value=1082,var_off=(0x2; 0x7fc))"}, 602 + }, 603 + }, 500 604 }; 501 605 502 606 static int probe_filter_length(const struct bpf_insn *fp)