@@ -441,6 +441,62 @@ static struct bpf_align_test tests[] = {
441
441
{23 , "R5=pkt(id=2,off=0,r=4,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc))" },
442
442
},
443
443
},
444
+ {
445
+ .descr = "dubious pointer arithmetic" ,
446
+ .insns = {
447
+ PREP_PKT_POINTERS ,
448
+ BPF_MOV64_IMM (BPF_REG_0 , 0 ),
449
+ /* ptr & const => unknown & const */
450
+ BPF_MOV64_REG (BPF_REG_5 , BPF_REG_2 ),
451
+ BPF_ALU64_IMM (BPF_AND , BPF_REG_5 , 0x40 ),
452
+ /* ptr << const => unknown << const */
453
+ BPF_MOV64_REG (BPF_REG_5 , BPF_REG_2 ),
454
+ BPF_ALU64_IMM (BPF_LSH , BPF_REG_5 , 2 ),
455
+ /* We have a (4n) value. Let's make a packet offset
456
+ * out of it. First add 14, to make it a (4n+2)
457
+ */
458
+ BPF_ALU64_IMM (BPF_ADD , BPF_REG_5 , 14 ),
459
+ /* Then make sure it's nonnegative */
460
+ BPF_JMP_IMM (BPF_JSGE , BPF_REG_5 , 0 , 1 ),
461
+ BPF_EXIT_INSN (),
462
+ /* Add it to packet pointer */
463
+ BPF_MOV64_REG (BPF_REG_6 , BPF_REG_2 ),
464
+ BPF_ALU64_REG (BPF_ADD , BPF_REG_6 , BPF_REG_5 ),
465
+ /* Check bounds and perform a read */
466
+ BPF_MOV64_REG (BPF_REG_4 , BPF_REG_6 ),
467
+ BPF_ALU64_IMM (BPF_ADD , BPF_REG_4 , 4 ),
468
+ BPF_JMP_REG (BPF_JGE , BPF_REG_3 , BPF_REG_4 , 1 ),
469
+ BPF_EXIT_INSN (),
470
+ BPF_LDX_MEM (BPF_W , BPF_REG_4 , BPF_REG_6 , 0 ),
471
+ BPF_EXIT_INSN (),
472
+ },
473
+ .prog_type = BPF_PROG_TYPE_SCHED_CLS ,
474
+ .result = REJECT ,
475
+ .matches = {
476
+ {4 , "R5=pkt(id=0,off=0,r=0,imm=0)" },
477
+ /* ptr & 0x40 == either 0 or 0x40 */
478
+ {5 , "R5=inv(id=0,umax_value=64,var_off=(0x0; 0x40))" },
479
+ /* ptr << 2 == unknown, (4n) */
480
+ {7 , "R5=inv(id=0,smax_value=9223372036854775804,umax_value=18446744073709551612,var_off=(0x0; 0xfffffffffffffffc))" },
481
+ /* (4n) + 14 == (4n+2). We blow our bounds, because
482
+ * the add could overflow.
483
+ */
484
+ {8 , "R5=inv(id=0,var_off=(0x2; 0xfffffffffffffffc))" },
485
+ /* Checked s>=0 */
486
+ {10 , "R5=inv(id=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))" },
487
+ /* packet pointer + nonnegative (4n+2) */
488
+ {12 , "R6=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))" },
489
+ {14 , "R4=pkt(id=1,off=4,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))" },
490
+ /* NET_IP_ALIGN + (4n+2) == (4n), alignment is fine.
491
+ * We checked the bounds, but it might have been able
492
+ * to overflow if the packet pointer started in the
493
+ * upper half of the address space.
494
+ * So we did not get a 'range' on R6, and the access
495
+ * attempt will fail.
496
+ */
497
+ {16 , "R6=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))" },
498
+ }
499
+ },
444
500
};
445
501
446
502
static int probe_filter_length (const struct bpf_insn * fp )
@@ -470,10 +526,15 @@ static int do_test_single(struct bpf_align_test *test)
470
526
fd_prog = bpf_verify_program (prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER ,
471
527
prog , prog_len , 1 , "GPL" , 0 ,
472
528
bpf_vlog , sizeof (bpf_vlog ), 2 );
473
- if (fd_prog < 0 ) {
529
+ if (fd_prog < 0 && test -> result != REJECT ) {
474
530
printf ("Failed to load program.\n" );
475
531
printf ("%s" , bpf_vlog );
476
532
ret = 1 ;
533
+ } else if (fd_prog >= 0 && test -> result == REJECT ) {
534
+ printf ("Unexpected success to load!\n" );
535
+ printf ("%s" , bpf_vlog );
536
+ ret = 1 ;
537
+ close (fd_prog );
477
538
} else {
478
539
ret = 0 ;
479
540
/* We make a local copy so that we can strtok() it */
@@ -506,7 +567,8 @@ static int do_test_single(struct bpf_align_test *test)
506
567
break ;
507
568
}
508
569
}
509
- close (fd_prog );
570
+ if (fd_prog >= 0 )
571
+ close (fd_prog );
510
572
}
511
573
return ret ;
512
574
}
0 commit comments