@@ -497,6 +497,110 @@ static struct bpf_align_test tests[] = {
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 )
0 commit comments