2017-05-10 11:43:51 -07:00
# include <asm/types.h>
# include <linux/types.h>
# include <stdint.h>
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <errno.h>
# include <string.h>
# include <stddef.h>
# include <stdbool.h>
# include <linux/unistd.h>
# include <linux/filter.h>
# include <linux/bpf_perf_event.h>
# include <linux/bpf.h>
# include <bpf/bpf.h>
# include "../../../include/linux/filter.h"
2018-02-26 22:34:32 +01:00
# include "bpf_rlimit.h"
2018-08-08 01:01:27 -07:00
# include "bpf_util.h"
2017-05-10 11:43:51 -07:00
# define MAX_INSNS 512
# define MAX_MATCHES 16
2017-08-07 15:27:34 +01:00
struct bpf_reg_match {
unsigned int line ;
const char * match ;
} ;
2017-05-10 11:43:51 -07:00
struct bpf_align_test {
const char * descr ;
struct bpf_insn insns [ MAX_INSNS ] ;
enum {
UNDEF ,
ACCEPT ,
REJECT
} result ;
enum bpf_prog_type prog_type ;
2017-08-07 15:27:34 +01:00
/* Matches must be in order of increasing line */
struct bpf_reg_match matches [ MAX_MATCHES ] ;
2017-05-10 11:43:51 -07:00
} ;
static struct bpf_align_test tests [ ] = {
2017-08-07 15:27:34 +01:00
/* Four tests of known constants. These aren't staggeringly
* interesting since we track exact values now .
*/
2017-05-10 11:43:51 -07:00
{
. descr = " mov " ,
. insns = {
BPF_MOV64_IMM ( BPF_REG_3 , 2 ) ,
BPF_MOV64_IMM ( BPF_REG_3 , 4 ) ,
BPF_MOV64_IMM ( BPF_REG_3 , 8 ) ,
BPF_MOV64_IMM ( BPF_REG_3 , 16 ) ,
BPF_MOV64_IMM ( BPF_REG_3 , 32 ) ,
BPF_MOV64_IMM ( BPF_REG_0 , 0 ) ,
BPF_EXIT_INSN ( ) ,
} ,
. prog_type = BPF_PROG_TYPE_SCHED_CLS ,
. matches = {
2017-08-07 15:27:34 +01:00
{ 1 , " R1=ctx(id=0,off=0,imm=0) " } ,
{ 1 , " R10=fp0 " } ,
2017-11-30 21:31:41 -08:00
{ 1 , " R3_w=inv2 " } ,
{ 2 , " R3_w=inv4 " } ,
{ 3 , " R3_w=inv8 " } ,
{ 4 , " R3_w=inv16 " } ,
{ 5 , " R3_w=inv32 " } ,
2017-05-10 11:43:51 -07:00
} ,
} ,
{
. descr = " shift " ,
. insns = {
BPF_MOV64_IMM ( BPF_REG_3 , 1 ) ,
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_3 , 1 ) ,
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_3 , 1 ) ,
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_3 , 1 ) ,
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_3 , 1 ) ,
BPF_ALU64_IMM ( BPF_RSH , BPF_REG_3 , 4 ) ,
BPF_MOV64_IMM ( BPF_REG_4 , 32 ) ,
BPF_ALU64_IMM ( BPF_RSH , BPF_REG_4 , 1 ) ,
BPF_ALU64_IMM ( BPF_RSH , BPF_REG_4 , 1 ) ,
BPF_ALU64_IMM ( BPF_RSH , BPF_REG_4 , 1 ) ,
BPF_ALU64_IMM ( BPF_RSH , BPF_REG_4 , 1 ) ,
BPF_MOV64_IMM ( BPF_REG_0 , 0 ) ,
BPF_EXIT_INSN ( ) ,
} ,
. prog_type = BPF_PROG_TYPE_SCHED_CLS ,
. matches = {
2017-08-07 15:27:34 +01:00
{ 1 , " R1=ctx(id=0,off=0,imm=0) " } ,
{ 1 , " R10=fp0 " } ,
2017-11-30 21:31:41 -08:00
{ 1 , " R3_w=inv1 " } ,
{ 2 , " R3_w=inv2 " } ,
{ 3 , " R3_w=inv4 " } ,
{ 4 , " R3_w=inv8 " } ,
{ 5 , " R3_w=inv16 " } ,
{ 6 , " R3_w=inv1 " } ,
{ 7 , " R4_w=inv32 " } ,
{ 8 , " R4_w=inv16 " } ,
{ 9 , " R4_w=inv8 " } ,
{ 10 , " R4_w=inv4 " } ,
{ 11 , " R4_w=inv2 " } ,
2017-05-10 11:43:51 -07:00
} ,
} ,
{
. descr = " addsub " ,
. insns = {
BPF_MOV64_IMM ( BPF_REG_3 , 4 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_3 , 4 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_3 , 2 ) ,
BPF_MOV64_IMM ( BPF_REG_4 , 8 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_4 , 4 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_4 , 2 ) ,
BPF_MOV64_IMM ( BPF_REG_0 , 0 ) ,
BPF_EXIT_INSN ( ) ,
} ,
. prog_type = BPF_PROG_TYPE_SCHED_CLS ,
. matches = {
2017-08-07 15:27:34 +01:00
{ 1 , " R1=ctx(id=0,off=0,imm=0) " } ,
{ 1 , " R10=fp0 " } ,
2017-11-30 21:31:41 -08:00
{ 1 , " R3_w=inv4 " } ,
{ 2 , " R3_w=inv8 " } ,
{ 3 , " R3_w=inv10 " } ,
{ 4 , " R4_w=inv8 " } ,
{ 5 , " R4_w=inv12 " } ,
{ 6 , " R4_w=inv14 " } ,
2017-05-10 11:43:51 -07:00
} ,
} ,
{
. descr = " mul " ,
. insns = {
BPF_MOV64_IMM ( BPF_REG_3 , 7 ) ,
BPF_ALU64_IMM ( BPF_MUL , BPF_REG_3 , 1 ) ,
BPF_ALU64_IMM ( BPF_MUL , BPF_REG_3 , 2 ) ,
BPF_ALU64_IMM ( BPF_MUL , BPF_REG_3 , 4 ) ,
BPF_MOV64_IMM ( BPF_REG_0 , 0 ) ,
BPF_EXIT_INSN ( ) ,
} ,
. prog_type = BPF_PROG_TYPE_SCHED_CLS ,
. matches = {
2017-08-07 15:27:34 +01:00
{ 1 , " R1=ctx(id=0,off=0,imm=0) " } ,
{ 1 , " R10=fp0 " } ,
2017-11-30 21:31:41 -08:00
{ 1 , " R3_w=inv7 " } ,
{ 2 , " R3_w=inv7 " } ,
{ 3 , " R3_w=inv14 " } ,
{ 4 , " R3_w=inv56 " } ,
2017-05-10 11:43:51 -07:00
} ,
} ,
2017-08-07 15:27:34 +01:00
/* Tests using unknown values */
2017-05-10 11:43:51 -07:00
# define PREP_PKT_POINTERS \
BPF_LDX_MEM ( BPF_W , BPF_REG_2 , BPF_REG_1 , \
offsetof ( struct __sk_buff , data ) ) , \
BPF_LDX_MEM ( BPF_W , BPF_REG_3 , BPF_REG_1 , \
offsetof ( struct __sk_buff , data_end ) )
# define LOAD_UNKNOWN(DST_REG) \
PREP_PKT_POINTERS , \
BPF_MOV64_REG ( BPF_REG_0 , BPF_REG_2 ) , \
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_0 , 8 ) , \
BPF_JMP_REG ( BPF_JGE , BPF_REG_3 , BPF_REG_0 , 1 ) , \
BPF_EXIT_INSN ( ) , \
BPF_LDX_MEM ( BPF_B , DST_REG , BPF_REG_2 , 0 )
{
. descr = " unknown shift " ,
. insns = {
LOAD_UNKNOWN ( BPF_REG_3 ) ,
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_3 , 1 ) ,
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_3 , 1 ) ,
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_3 , 1 ) ,
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_3 , 1 ) ,
LOAD_UNKNOWN ( BPF_REG_4 ) ,
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_4 , 5 ) ,
BPF_ALU64_IMM ( BPF_RSH , BPF_REG_4 , 1 ) ,
BPF_ALU64_IMM ( BPF_RSH , BPF_REG_4 , 1 ) ,
BPF_ALU64_IMM ( BPF_RSH , BPF_REG_4 , 1 ) ,
BPF_ALU64_IMM ( BPF_RSH , BPF_REG_4 , 1 ) ,
BPF_MOV64_IMM ( BPF_REG_0 , 0 ) ,
BPF_EXIT_INSN ( ) ,
} ,
. prog_type = BPF_PROG_TYPE_SCHED_CLS ,
. matches = {
2017-08-07 15:27:34 +01:00
{ 7 , " R0=pkt(id=0,off=8,r=8,imm=0) " } ,
2017-11-30 21:31:41 -08:00
{ 7 , " R3_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) " } ,
{ 8 , " R3_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe)) " } ,
{ 9 , " R3_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
{ 10 , " R3_w=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8)) " } ,
{ 11 , " R3_w=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0)) " } ,
2017-08-07 15:27:34 +01:00
{ 18 , " R3=pkt_end(id=0,off=0,imm=0) " } ,
2017-11-30 21:31:41 -08:00
{ 18 , " R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) " } ,
{ 19 , " R4_w=inv(id=0,umax_value=8160,var_off=(0x0; 0x1fe0)) " } ,
{ 20 , " R4_w=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0)) " } ,
{ 21 , " R4_w=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8)) " } ,
{ 22 , " R4_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
{ 23 , " R4_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe)) " } ,
2017-05-10 11:43:51 -07:00
} ,
} ,
{
. descr = " unknown mul " ,
. insns = {
LOAD_UNKNOWN ( BPF_REG_3 ) ,
BPF_MOV64_REG ( BPF_REG_4 , BPF_REG_3 ) ,
BPF_ALU64_IMM ( BPF_MUL , BPF_REG_4 , 1 ) ,
BPF_MOV64_REG ( BPF_REG_4 , BPF_REG_3 ) ,
BPF_ALU64_IMM ( BPF_MUL , BPF_REG_4 , 2 ) ,
BPF_MOV64_REG ( BPF_REG_4 , BPF_REG_3 ) ,
BPF_ALU64_IMM ( BPF_MUL , BPF_REG_4 , 4 ) ,
BPF_MOV64_REG ( BPF_REG_4 , BPF_REG_3 ) ,
BPF_ALU64_IMM ( BPF_MUL , BPF_REG_4 , 8 ) ,
BPF_ALU64_IMM ( BPF_MUL , BPF_REG_4 , 2 ) ,
BPF_MOV64_IMM ( BPF_REG_0 , 0 ) ,
BPF_EXIT_INSN ( ) ,
} ,
. prog_type = BPF_PROG_TYPE_SCHED_CLS ,
. matches = {
2017-11-30 21:31:41 -08:00
{ 7 , " R3_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) " } ,
{ 8 , " R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) " } ,
{ 9 , " R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) " } ,
{ 10 , " R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) " } ,
{ 11 , " R4_w=inv(id=0,umax_value=510,var_off=(0x0; 0x1fe)) " } ,
{ 12 , " R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) " } ,
{ 13 , " R4_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
{ 14 , " R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) " } ,
{ 15 , " R4_w=inv(id=0,umax_value=2040,var_off=(0x0; 0x7f8)) " } ,
{ 16 , " R4_w=inv(id=0,umax_value=4080,var_off=(0x0; 0xff0)) " } ,
2017-05-10 11:43:51 -07:00
} ,
} ,
{
. descr = " packet const offset " ,
. insns = {
PREP_PKT_POINTERS ,
BPF_MOV64_REG ( BPF_REG_5 , BPF_REG_2 ) ,
BPF_MOV64_IMM ( BPF_REG_0 , 0 ) ,
/* Skip over ethernet header. */
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_5 , 14 ) ,
BPF_MOV64_REG ( BPF_REG_4 , BPF_REG_5 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_4 , 4 ) ,
BPF_JMP_REG ( BPF_JGE , BPF_REG_3 , BPF_REG_4 , 1 ) ,
BPF_EXIT_INSN ( ) ,
BPF_LDX_MEM ( BPF_B , BPF_REG_4 , BPF_REG_5 , 0 ) ,
BPF_LDX_MEM ( BPF_B , BPF_REG_4 , BPF_REG_5 , 1 ) ,
BPF_LDX_MEM ( BPF_B , BPF_REG_4 , BPF_REG_5 , 2 ) ,
BPF_LDX_MEM ( BPF_B , BPF_REG_4 , BPF_REG_5 , 3 ) ,
BPF_LDX_MEM ( BPF_H , BPF_REG_4 , BPF_REG_5 , 0 ) ,
BPF_LDX_MEM ( BPF_H , BPF_REG_4 , BPF_REG_5 , 2 ) ,
BPF_LDX_MEM ( BPF_W , BPF_REG_4 , BPF_REG_5 , 0 ) ,
BPF_MOV64_IMM ( BPF_REG_0 , 0 ) ,
BPF_EXIT_INSN ( ) ,
} ,
. prog_type = BPF_PROG_TYPE_SCHED_CLS ,
. matches = {
2017-11-30 21:31:41 -08:00
{ 4 , " R5_w=pkt(id=0,off=0,r=0,imm=0) " } ,
{ 5 , " R5_w=pkt(id=0,off=14,r=0,imm=0) " } ,
{ 6 , " R4_w=pkt(id=0,off=14,r=0,imm=0) " } ,
2017-08-07 15:27:34 +01:00
{ 10 , " R2=pkt(id=0,off=0,r=18,imm=0) " } ,
{ 10 , " R5=pkt(id=0,off=14,r=18,imm=0) " } ,
2017-11-30 21:31:41 -08:00
{ 10 , " R4_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) " } ,
{ 14 , " R4_w=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff)) " } ,
{ 15 , " R4_w=inv(id=0,umax_value=65535,var_off=(0x0; 0xffff)) " } ,
2017-05-10 11:43:51 -07:00
} ,
} ,
{
. descr = " packet variable offset " ,
. insns = {
LOAD_UNKNOWN ( BPF_REG_6 ) ,
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_6 , 2 ) ,
/* First, add a constant to the R5 packet pointer,
* then a variable with a known alignment .
*/
BPF_MOV64_REG ( BPF_REG_5 , BPF_REG_2 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_5 , 14 ) ,
BPF_ALU64_REG ( BPF_ADD , BPF_REG_5 , BPF_REG_6 ) ,
BPF_MOV64_REG ( BPF_REG_4 , BPF_REG_5 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_4 , 4 ) ,
BPF_JMP_REG ( BPF_JGE , BPF_REG_3 , BPF_REG_4 , 1 ) ,
BPF_EXIT_INSN ( ) ,
BPF_LDX_MEM ( BPF_W , BPF_REG_4 , BPF_REG_5 , 0 ) ,
/* Now, test in the other direction. Adding first
* the variable offset to R5 , then the constant .
*/
BPF_MOV64_REG ( BPF_REG_5 , BPF_REG_2 ) ,
BPF_ALU64_REG ( BPF_ADD , BPF_REG_5 , BPF_REG_6 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_5 , 14 ) ,
BPF_MOV64_REG ( BPF_REG_4 , BPF_REG_5 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_4 , 4 ) ,
BPF_JMP_REG ( BPF_JGE , BPF_REG_3 , BPF_REG_4 , 1 ) ,
BPF_EXIT_INSN ( ) ,
BPF_LDX_MEM ( BPF_W , BPF_REG_4 , BPF_REG_5 , 0 ) ,
2017-05-11 19:30:02 -07:00
/* Test multiple accumulations of unknown values
* into a packet pointer .
*/
BPF_MOV64_REG ( BPF_REG_5 , BPF_REG_2 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_5 , 14 ) ,
BPF_ALU64_REG ( BPF_ADD , BPF_REG_5 , BPF_REG_6 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_5 , 4 ) ,
BPF_ALU64_REG ( BPF_ADD , BPF_REG_5 , BPF_REG_6 ) ,
BPF_MOV64_REG ( BPF_REG_4 , BPF_REG_5 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_4 , 4 ) ,
BPF_JMP_REG ( BPF_JGE , BPF_REG_3 , BPF_REG_4 , 1 ) ,
BPF_EXIT_INSN ( ) ,
BPF_LDX_MEM ( BPF_W , BPF_REG_4 , BPF_REG_5 , 0 ) ,
2017-05-10 11:43:51 -07:00
BPF_MOV64_IMM ( BPF_REG_0 , 0 ) ,
BPF_EXIT_INSN ( ) ,
} ,
. prog_type = BPF_PROG_TYPE_SCHED_CLS ,
. matches = {
/* Calculated offset in R6 has unknown value, but known
* alignment of 4.
*/
2017-08-07 15:27:34 +01:00
{ 8 , " R2=pkt(id=0,off=0,r=8,imm=0) " } ,
2017-11-30 21:31:41 -08:00
{ 8 , " R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
2017-08-07 15:27:34 +01:00
/* Offset is added to packet pointer R5, resulting in
* known fixed offset , and variable offset from R6 .
2017-05-10 11:43:51 -07:00
*/
2017-11-30 21:31:41 -08:00
{ 11 , " R5_w=pkt(id=1,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
2017-05-10 11:43:51 -07:00
/* At the time the word size load is performed from R5,
* it ' s total offset is NET_IP_ALIGN + reg - > off ( 0 ) +
* reg - > aux_off ( 14 ) which is 16. Then the variable
* offset is considered using reg - > aux_off_align which
* is 4 and meets the load ' s requirements .
*/
2017-08-07 15:27:34 +01:00
{ 15 , " R4=pkt(id=1,off=18,r=18,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
{ 15 , " R5=pkt(id=1,off=14,r=18,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
2017-05-10 11:43:51 -07:00
/* Variable offset is added to R5 packet pointer,
* resulting in auxiliary alignment of 4.
*/
2017-11-30 21:31:41 -08:00
{ 18 , " R5_w=pkt(id=2,off=0,r=0,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
2017-05-10 11:43:51 -07:00
/* Constant offset is added to R5, resulting in
* reg - > off of 14.
*/
2017-11-30 21:31:41 -08:00
{ 19 , " R5_w=pkt(id=2,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
2017-05-10 11:43:51 -07:00
/* At the time the word size load is performed from R5,
2017-08-07 15:27:34 +01:00
* its total fixed offset is NET_IP_ALIGN + reg - > off
* ( 14 ) which is 16. Then the variable offset is 4 - byte
* aligned , so the total offset is 4 - byte aligned and
* meets the load ' s requirements .
2017-05-10 11:43:51 -07:00
*/
2017-08-07 15:27:34 +01:00
{ 23 , " R4=pkt(id=2,off=18,r=18,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
{ 23 , " R5=pkt(id=2,off=14,r=18,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
2017-05-11 19:30:02 -07:00
/* Constant offset is added to R5 packet pointer,
* resulting in reg - > off value of 14.
*/
2017-11-30 21:31:41 -08:00
{ 26 , " R5_w=pkt(id=0,off=14,r=8 " } ,
2017-08-07 15:27:34 +01:00
/* Variable offset is added to R5, resulting in a
* variable offset of ( 4 n ) .
2017-05-11 19:30:02 -07:00
*/
2017-11-30 21:31:41 -08:00
{ 27 , " R5_w=pkt(id=3,off=14,r=0,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
2017-08-07 15:27:34 +01:00
/* Constant is added to R5 again, setting reg->off to 18. */
2017-11-30 21:31:41 -08:00
{ 28 , " R5_w=pkt(id=3,off=18,r=0,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
2017-08-07 15:27:34 +01:00
/* And once more we add a variable; resulting var_off
* is still ( 4 n ) , fixed offset is not changed .
* Also , we create a new reg - > id .
2017-05-11 19:30:02 -07:00
*/
2017-11-30 21:31:41 -08:00
{ 29 , " R5_w=pkt(id=4,off=18,r=0,umax_value=2040,var_off=(0x0; 0x7fc)) " } ,
2017-05-11 19:30:02 -07:00
/* At the time the word size load is performed from R5,
2017-08-07 15:27:34 +01:00
* its total fixed offset is NET_IP_ALIGN + reg - > off ( 18 )
* which is 20. Then the variable offset is ( 4 n ) , so
* the total offset is 4 - byte aligned and meets the
* load ' s requirements .
2017-05-11 19:30:02 -07:00
*/
2017-08-07 15:27:34 +01:00
{ 33 , " R4=pkt(id=4,off=22,r=22,umax_value=2040,var_off=(0x0; 0x7fc)) " } ,
{ 33 , " R5=pkt(id=4,off=18,r=22,umax_value=2040,var_off=(0x0; 0x7fc)) " } ,
2017-05-10 11:43:51 -07:00
} ,
} ,
2017-08-07 15:28:00 +01:00
{
. descr = " packet variable offset 2 " ,
. insns = {
/* Create an unknown offset, (4n+2)-aligned */
LOAD_UNKNOWN ( BPF_REG_6 ) ,
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_6 , 2 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_6 , 14 ) ,
/* Add it to the packet pointer */
BPF_MOV64_REG ( BPF_REG_5 , BPF_REG_2 ) ,
BPF_ALU64_REG ( BPF_ADD , BPF_REG_5 , BPF_REG_6 ) ,
/* Check bounds and perform a read */
BPF_MOV64_REG ( BPF_REG_4 , BPF_REG_5 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_4 , 4 ) ,
BPF_JMP_REG ( BPF_JGE , BPF_REG_3 , BPF_REG_4 , 1 ) ,
BPF_EXIT_INSN ( ) ,
BPF_LDX_MEM ( BPF_W , BPF_REG_6 , BPF_REG_5 , 0 ) ,
/* Make a (4n) offset from the value we just read */
BPF_ALU64_IMM ( BPF_AND , BPF_REG_6 , 0xff ) ,
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_6 , 2 ) ,
/* Add it to the packet pointer */
BPF_ALU64_REG ( BPF_ADD , BPF_REG_5 , BPF_REG_6 ) ,
/* Check bounds and perform a read */
BPF_MOV64_REG ( BPF_REG_4 , BPF_REG_5 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_4 , 4 ) ,
BPF_JMP_REG ( BPF_JGE , BPF_REG_3 , BPF_REG_4 , 1 ) ,
BPF_EXIT_INSN ( ) ,
BPF_LDX_MEM ( BPF_W , BPF_REG_6 , BPF_REG_5 , 0 ) ,
BPF_MOV64_IMM ( BPF_REG_0 , 0 ) ,
BPF_EXIT_INSN ( ) ,
} ,
. prog_type = BPF_PROG_TYPE_SCHED_CLS ,
. matches = {
/* Calculated offset in R6 has unknown value, but known
* alignment of 4.
*/
{ 8 , " R2=pkt(id=0,off=0,r=8,imm=0) " } ,
2017-11-30 21:31:41 -08:00
{ 8 , " R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
2017-08-07 15:28:00 +01:00
/* Adding 14 makes R6 be (4n+2) */
2017-11-30 21:31:41 -08:00
{ 9 , " R6_w=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)) " } ,
2017-08-07 15:28:00 +01:00
/* Packet pointer has (4n+2) offset */
2017-11-30 21:31:41 -08:00
{ 11 , " R5_w=pkt(id=1,off=0,r=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)) " } ,
2017-08-07 15:28:00 +01:00
{ 13 , " R4=pkt(id=1,off=4,r=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)) " } ,
/* At the time the word size load is performed from R5,
* its total fixed offset is NET_IP_ALIGN + reg - > off ( 0 )
* which is 2. Then the variable offset is ( 4 n + 2 ) , so
* the total offset is 4 - byte aligned and meets the
* load ' s requirements .
*/
{ 15 , " R5=pkt(id=1,off=0,r=4,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)) " } ,
/* Newly read value in R6 was shifted left by 2, so has
* known alignment of 4.
*/
2017-11-30 21:31:41 -08:00
{ 18 , " R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
2017-08-07 15:28:00 +01:00
/* Added (4n) to packet pointer's (4n+2) var_off, giving
* another ( 4 n + 2 ) .
*/
2017-11-30 21:31:41 -08:00
{ 19 , " R5_w=pkt(id=2,off=0,r=0,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc)) " } ,
2017-08-07 15:28:00 +01:00
{ 21 , " R4=pkt(id=2,off=4,r=0,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc)) " } ,
/* At the time the word size load is performed from R5,
* its total fixed offset is NET_IP_ALIGN + reg - > off ( 0 )
* which is 2. Then the variable offset is ( 4 n + 2 ) , so
* the total offset is 4 - byte aligned and meets the
* load ' s requirements .
*/
{ 23 , " R5=pkt(id=2,off=0,r=4,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc)) " } ,
} ,
} ,
2017-08-07 15:28:45 +01:00
{
. descr = " dubious pointer arithmetic " ,
. insns = {
PREP_PKT_POINTERS ,
BPF_MOV64_IMM ( BPF_REG_0 , 0 ) ,
2018-01-23 20:05:51 -08:00
/* (ptr - ptr) << 2 */
BPF_MOV64_REG ( BPF_REG_5 , BPF_REG_3 ) ,
BPF_ALU64_REG ( BPF_SUB , BPF_REG_5 , BPF_REG_2 ) ,
2017-08-07 15:28:45 +01:00
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_5 , 2 ) ,
/* We have a (4n) value. Let's make a packet offset
* out of it . First add 14 , to make it a ( 4 n + 2 )
*/
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_5 , 14 ) ,
/* Then make sure it's nonnegative */
BPF_JMP_IMM ( BPF_JSGE , BPF_REG_5 , 0 , 1 ) ,
BPF_EXIT_INSN ( ) ,
/* Add it to packet pointer */
BPF_MOV64_REG ( BPF_REG_6 , BPF_REG_2 ) ,
BPF_ALU64_REG ( BPF_ADD , BPF_REG_6 , BPF_REG_5 ) ,
/* Check bounds and perform a read */
BPF_MOV64_REG ( BPF_REG_4 , BPF_REG_6 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_4 , 4 ) ,
BPF_JMP_REG ( BPF_JGE , BPF_REG_3 , BPF_REG_4 , 1 ) ,
BPF_EXIT_INSN ( ) ,
BPF_LDX_MEM ( BPF_W , BPF_REG_4 , BPF_REG_6 , 0 ) ,
BPF_EXIT_INSN ( ) ,
} ,
. prog_type = BPF_PROG_TYPE_SCHED_CLS ,
. result = REJECT ,
. matches = {
2018-01-23 20:05:51 -08:00
{ 4 , " R5_w=pkt_end(id=0,off=0,imm=0) " } ,
/* (ptr - ptr) << 2 == unknown, (4n) */
{ 6 , " R5_w=inv(id=0,smax_value=9223372036854775804,umax_value=18446744073709551612,var_off=(0x0; 0xfffffffffffffffc)) " } ,
/* (4n) + 14 == (4n+2). We blow our bounds, because
* the add could overflow .
*/
{ 7 , " R5=inv(id=0,var_off=(0x2; 0xfffffffffffffffc)) " } ,
/* Checked s>=0 */
{ 9 , " R5=inv(id=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc)) " } ,
/* packet pointer + nonnegative (4n+2) */
{ 11 , " R6_w=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc)) " } ,
{ 13 , " R4=pkt(id=1,off=4,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc)) " } ,
/* NET_IP_ALIGN + (4n+2) == (4n), alignment is fine.
* We checked the bounds , but it might have been able
* to overflow if the packet pointer started in the
* upper half of the address space .
* So we did not get a ' range ' on R6 , and the access
* attempt will fail .
*/
{ 15 , " R6=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc)) " } ,
2017-08-07 15:28:45 +01:00
}
} ,
2017-08-07 15:29:34 +01:00
{
. descr = " variable subtraction " ,
. insns = {
/* Create an unknown offset, (4n+2)-aligned */
LOAD_UNKNOWN ( BPF_REG_6 ) ,
BPF_MOV64_REG ( BPF_REG_7 , BPF_REG_6 ) ,
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_6 , 2 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_6 , 14 ) ,
/* Create another unknown, (4n)-aligned, and subtract
* it from the first one
*/
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_7 , 2 ) ,
BPF_ALU64_REG ( BPF_SUB , BPF_REG_6 , BPF_REG_7 ) ,
/* Bounds-check the result */
BPF_JMP_IMM ( BPF_JSGE , BPF_REG_6 , 0 , 1 ) ,
BPF_EXIT_INSN ( ) ,
/* Add it to the packet pointer */
BPF_MOV64_REG ( BPF_REG_5 , BPF_REG_2 ) ,
BPF_ALU64_REG ( BPF_ADD , BPF_REG_5 , BPF_REG_6 ) ,
/* Check bounds and perform a read */
BPF_MOV64_REG ( BPF_REG_4 , BPF_REG_5 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_4 , 4 ) ,
BPF_JMP_REG ( BPF_JGE , BPF_REG_3 , BPF_REG_4 , 1 ) ,
BPF_EXIT_INSN ( ) ,
BPF_LDX_MEM ( BPF_W , BPF_REG_6 , BPF_REG_5 , 0 ) ,
BPF_EXIT_INSN ( ) ,
} ,
. prog_type = BPF_PROG_TYPE_SCHED_CLS ,
. matches = {
/* Calculated offset in R6 has unknown value, but known
* alignment of 4.
*/
{ 7 , " R2=pkt(id=0,off=0,r=8,imm=0) " } ,
2017-11-30 21:31:41 -08:00
{ 9 , " R6_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
2017-08-07 15:29:34 +01:00
/* Adding 14 makes R6 be (4n+2) */
2017-11-30 21:31:41 -08:00
{ 10 , " R6_w=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)) " } ,
2017-08-07 15:29:34 +01:00
/* New unknown value in R7 is (4n) */
2017-11-30 21:31:41 -08:00
{ 11 , " R7_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc)) " } ,
2017-08-07 15:29:34 +01:00
/* Subtracting it from R6 blows our unsigned bounds */
{ 12 , " R6=inv(id=0,smin_value=-1006,smax_value=1034,var_off=(0x2; 0xfffffffffffffffc)) " } ,
/* Checked s>= 0 */
{ 14 , " R6=inv(id=0,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc)) " } ,
/* At the time the word size load is performed from R5,
* its total fixed offset is NET_IP_ALIGN + reg - > off ( 0 )
* which is 2. Then the variable offset is ( 4 n + 2 ) , so
* the total offset is 4 - byte aligned and meets the
* load ' s requirements .
*/
{ 20 , " R5=pkt(id=1,off=0,r=4,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc)) " } ,
} ,
} ,
{
. descr = " pointer variable subtraction " ,
. insns = {
/* Create an unknown offset, (4n+2)-aligned and bounded
* to [ 14 , 74 ]
*/
LOAD_UNKNOWN ( BPF_REG_6 ) ,
BPF_MOV64_REG ( BPF_REG_7 , BPF_REG_6 ) ,
BPF_ALU64_IMM ( BPF_AND , BPF_REG_6 , 0xf ) ,
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_6 , 2 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_6 , 14 ) ,
/* Subtract it from the packet pointer */
BPF_MOV64_REG ( BPF_REG_5 , BPF_REG_2 ) ,
BPF_ALU64_REG ( BPF_SUB , BPF_REG_5 , BPF_REG_6 ) ,
/* Create another unknown, (4n)-aligned and >= 74.
* That in fact means > = 76 , since 74 % 4 = = 2
*/
BPF_ALU64_IMM ( BPF_LSH , BPF_REG_7 , 2 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_7 , 76 ) ,
/* Add it to the packet pointer */
BPF_ALU64_REG ( BPF_ADD , BPF_REG_5 , BPF_REG_7 ) ,
/* Check bounds and perform a read */
BPF_MOV64_REG ( BPF_REG_4 , BPF_REG_5 ) ,
BPF_ALU64_IMM ( BPF_ADD , BPF_REG_4 , 4 ) ,
BPF_JMP_REG ( BPF_JGE , BPF_REG_3 , BPF_REG_4 , 1 ) ,
BPF_EXIT_INSN ( ) ,
BPF_LDX_MEM ( BPF_W , BPF_REG_6 , BPF_REG_5 , 0 ) ,
BPF_EXIT_INSN ( ) ,
} ,
. prog_type = BPF_PROG_TYPE_SCHED_CLS ,
. matches = {
/* Calculated offset in R6 has unknown value, but known
* alignment of 4.
*/
{ 7 , " R2=pkt(id=0,off=0,r=8,imm=0) " } ,
2017-11-30 21:31:41 -08:00
{ 10 , " R6_w=inv(id=0,umax_value=60,var_off=(0x0; 0x3c)) " } ,
2017-08-07 15:29:34 +01:00
/* Adding 14 makes R6 be (4n+2) */
2017-11-30 21:31:41 -08:00
{ 11 , " R6_w=inv(id=0,umin_value=14,umax_value=74,var_off=(0x2; 0x7c)) " } ,
2017-08-07 15:29:34 +01:00
/* Subtracting from packet pointer overflows ubounds */
2017-11-30 21:31:41 -08:00
{ 13 , " R5_w=pkt(id=1,off=0,r=8,umin_value=18446744073709551542,umax_value=18446744073709551602,var_off=(0xffffffffffffff82; 0x7c)) " } ,
2017-08-07 15:29:34 +01:00
/* New unknown value in R7 is (4n), >= 76 */
2017-11-30 21:31:41 -08:00
{ 15 , " R7_w=inv(id=0,umin_value=76,umax_value=1096,var_off=(0x0; 0x7fc)) " } ,
2017-08-07 15:29:34 +01:00
/* Adding it to packet pointer gives nice bounds again */
2017-11-30 21:31:41 -08:00
{ 16 , " R5_w=pkt(id=2,off=0,r=0,umin_value=2,umax_value=1082,var_off=(0x2; 0x7fc)) " } ,
2017-08-07 15:29:34 +01:00
/* At the time the word size load is performed from R5,
* its total fixed offset is NET_IP_ALIGN + reg - > off ( 0 )
* which is 2. Then the variable offset is ( 4 n + 2 ) , so
* the total offset is 4 - byte aligned and meets the
* load ' s requirements .
*/
{ 20 , " R5=pkt(id=2,off=0,r=4,umin_value=2,umax_value=1082,var_off=(0x2; 0x7fc)) " } ,
} ,
} ,
2017-05-10 11:43:51 -07:00
} ;
static int probe_filter_length ( const struct bpf_insn * fp )
{
int len ;
for ( len = MAX_INSNS - 1 ; len > 0 ; - - len )
if ( fp [ len ] . code ! = 0 | | fp [ len ] . imm ! = 0 )
break ;
return len + 1 ;
}
static char bpf_vlog [ 32768 ] ;
static int do_test_single ( struct bpf_align_test * test )
{
struct bpf_insn * prog = test - > insns ;
int prog_type = test - > prog_type ;
2017-08-07 15:27:34 +01:00
char bpf_vlog_copy [ 32768 ] ;
const char * line_ptr ;
int cur_line = - 1 ;
2017-05-10 11:43:51 -07:00
int prog_len , i ;
int fd_prog ;
int ret ;
prog_len = probe_filter_length ( prog ) ;
fd_prog = bpf_verify_program ( prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER ,
prog , prog_len , 1 , " GPL " , 0 ,
2017-07-21 00:00:22 +02:00
bpf_vlog , sizeof ( bpf_vlog ) , 2 ) ;
2017-08-07 15:28:45 +01:00
if ( fd_prog < 0 & & test - > result ! = REJECT ) {
2017-05-10 11:43:51 -07:00
printf ( " Failed to load program. \n " ) ;
printf ( " %s " , bpf_vlog ) ;
ret = 1 ;
2017-08-07 15:28:45 +01:00
} else if ( fd_prog > = 0 & & test - > result = = REJECT ) {
printf ( " Unexpected success to load! \n " ) ;
printf ( " %s " , bpf_vlog ) ;
ret = 1 ;
close ( fd_prog ) ;
2017-05-10 11:43:51 -07:00
} else {
ret = 0 ;
2017-08-07 15:27:34 +01:00
/* We make a local copy so that we can strtok() it */
strncpy ( bpf_vlog_copy , bpf_vlog , sizeof ( bpf_vlog_copy ) ) ;
line_ptr = strtok ( bpf_vlog_copy , " \n " ) ;
2017-05-10 11:43:51 -07:00
for ( i = 0 ; i < MAX_MATCHES ; i + + ) {
2017-08-07 15:27:34 +01:00
struct bpf_reg_match m = test - > matches [ i ] ;
2017-05-10 11:43:51 -07:00
2017-08-07 15:27:34 +01:00
if ( ! m . match )
2017-05-10 11:43:51 -07:00
break ;
2017-08-07 15:27:34 +01:00
while ( line_ptr ) {
cur_line = - 1 ;
sscanf ( line_ptr , " %u: " , & cur_line ) ;
if ( cur_line = = m . line )
break ;
line_ptr = strtok ( NULL , " \n " ) ;
}
if ( ! line_ptr ) {
printf ( " Failed to find line %u for match: %s \n " ,
m . line , m . match ) ;
ret = 1 ;
printf ( " %s " , bpf_vlog ) ;
break ;
}
if ( ! strstr ( line_ptr , m . match ) ) {
printf ( " Failed to find match %u: %s \n " ,
m . line , m . match ) ;
2017-05-10 11:43:51 -07:00
ret = 1 ;
printf ( " %s " , bpf_vlog ) ;
break ;
}
}
2017-08-07 15:28:45 +01:00
if ( fd_prog > = 0 )
close ( fd_prog ) ;
2017-05-10 11:43:51 -07:00
}
return ret ;
}
static int do_test ( unsigned int from , unsigned int to )
{
int all_pass = 0 ;
int all_fail = 0 ;
unsigned int i ;
for ( i = from ; i < to ; i + + ) {
struct bpf_align_test * test = & tests [ i ] ;
int fail ;
printf ( " Test %3d: %s ... " ,
i , test - > descr ) ;
fail = do_test_single ( test ) ;
if ( fail ) {
all_fail + + ;
printf ( " FAIL \n " ) ;
} else {
all_pass + + ;
printf ( " PASS \n " ) ;
}
}
printf ( " Results: %d pass %d fail \n " ,
all_pass , all_fail ) ;
2017-06-13 15:17:19 +02:00
return all_fail ? EXIT_FAILURE : EXIT_SUCCESS ;
2017-05-10 11:43:51 -07:00
}
int main ( int argc , char * * argv )
{
unsigned int from = 0 , to = ARRAY_SIZE ( tests ) ;
if ( argc = = 3 ) {
unsigned int l = atoi ( argv [ argc - 2 ] ) ;
unsigned int u = atoi ( argv [ argc - 1 ] ) ;
if ( l < to & & u < to ) {
from = l ;
to = u + 1 ;
}
} else if ( argc = = 2 ) {
unsigned int t = atoi ( argv [ argc - 1 ] ) ;
if ( t < to ) {
from = t ;
to = t + 1 ;
}
}
return do_test ( from , to ) ;
}