nfp: bpf: allow stack accesses via modified stack registers

As long as the verifier tells us the stack offset exactly we
can render the LMEM reads quite easily.  Simply make sure that
the offset is constant for a given instruction and add it to
the instruction's offset.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jakub Kicinski 2017-10-23 11:58:11 -07:00 committed by David S. Miller
parent 9a90c83c09
commit d348848063
3 changed files with 33 additions and 17 deletions

View File

@ -771,9 +771,10 @@ wrp_lmem_store(struct nfp_prog *nfp_prog, u8 src, u8 src_byte, s32 off,
static int
mem_op_stack(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
unsigned int size, u8 gpr, bool clr_gpr, lmem_step step)
unsigned int size, unsigned int ptr_off, u8 gpr, bool clr_gpr,
lmem_step step)
{
s32 off = nfp_prog->stack_depth + meta->insn.off;
s32 off = nfp_prog->stack_depth + meta->insn.off + ptr_off;
bool first = true, last;
u8 prev_gpr = 255;
u32 gpr_byte = 0;
@ -1311,10 +1312,10 @@ static int data_ind_ld4(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
static int
mem_ldx_stack(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
unsigned int size)
unsigned int size, unsigned int ptr_off)
{
return mem_op_stack(nfp_prog, meta, size, meta->insn.dst_reg * 2, true,
wrp_lmem_load);
return mem_op_stack(nfp_prog, meta, size, ptr_off,
meta->insn.dst_reg * 2, true, wrp_lmem_load);
}
static int mem_ldx_skb(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
@ -1401,7 +1402,8 @@ mem_ldx(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
return mem_ldx_data(nfp_prog, meta, size);
if (meta->ptr.type == PTR_TO_STACK)
return mem_ldx_stack(nfp_prog, meta, size);
return mem_ldx_stack(nfp_prog, meta, size,
meta->ptr.off + meta->ptr.var_off.value);
return -EOPNOTSUPP;
}
@ -1482,10 +1484,10 @@ mem_stx_data(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
static int
mem_stx_stack(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
unsigned int size)
unsigned int size, unsigned int ptr_off)
{
return mem_op_stack(nfp_prog, meta, size, meta->insn.src_reg * 2, false,
wrp_lmem_store);
return mem_op_stack(nfp_prog, meta, size, ptr_off,
meta->insn.src_reg * 2, false, wrp_lmem_store);
}
static int
@ -1496,7 +1498,8 @@ mem_stx(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
return mem_stx_data(nfp_prog, meta, size);
if (meta->ptr.type == PTR_TO_STACK)
return mem_stx_stack(nfp_prog, meta, size);
return mem_stx_stack(nfp_prog, meta, size,
meta->ptr.off + meta->ptr.var_off.value);
return -EOPNOTSUPP;
}

View File

@ -56,6 +56,7 @@ enum br_special {
enum static_regs {
STATIC_REG_IMM = 21, /* Bank AB */
STATIC_REG_STACK = 22, /* Bank A */
STATIC_REG_PKT_LEN = 22, /* Bank B */
};
@ -74,6 +75,8 @@ enum nfp_bpf_action_type {
#define pv_len(np) reg_lm(1, PKT_VEC_PKT_LEN)
#define pv_ctm_ptr(np) reg_lm(1, PKT_VEC_PKT_PTR)
#define stack_reg(np) reg_a(STATIC_REG_STACK)
#define stack_imm(np) imm_b(np)
#define plen_reg(np) reg_b(STATIC_REG_PKT_LEN)
#define pptr_reg(np) pv_ctm_ptr(np)
#define imm_a(np) reg_a(STATIC_REG_IMM)

View File

@ -111,19 +111,29 @@ nfp_bpf_check_exit(struct nfp_prog *nfp_prog,
return 0;
}
static int nfp_bpf_check_stack_access(const struct bpf_reg_state *reg)
static int
nfp_bpf_check_stack_access(struct nfp_insn_meta *meta,
const struct bpf_reg_state *reg)
{
s32 old_off, new_off;
if (!tnum_is_const(reg->var_off)) {
pr_info("variable ptr stack access\n");
return -EINVAL;
}
if (reg->var_off.value || reg->off) {
pr_info("stack access via modified register\n");
return -EINVAL;
}
if (meta->ptr.type == NOT_INIT)
return 0;
return 0;
old_off = meta->ptr.off + meta->ptr.var_off.value;
new_off = reg->off + reg->var_off.value;
if (old_off == new_off)
return 0;
pr_info("stack access changed location was:%d is:%d\n",
old_off, new_off);
return -EINVAL;
}
static int
@ -141,7 +151,7 @@ nfp_bpf_check_ptr(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
}
if (reg->type == PTR_TO_STACK) {
err = nfp_bpf_check_stack_access(reg);
err = nfp_bpf_check_stack_access(meta, reg);
if (err)
return err;
}