Skip to content

Commit

Permalink
Merge branch 'bpf-misc'
Browse files Browse the repository at this point in the history
Daniel Borkmann says:

====================
Misc BPF improvements

This series adds various misc improvements to BPF, f.e. allowing
skb_load_bytes() helper to be used with filter/reuseport programs
to facilitate programming, test cases for program tag, etc. For
details, please see individual patches.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jan 24, 2017
2 parents 1870241 + 3fadc80 commit bef4e17
Show file tree
Hide file tree
Showing 6 changed files with 364 additions and 52 deletions.
1 change: 1 addition & 0 deletions include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@ enum bpf_func_id {
/* BPF_FUNC_l4_csum_replace flags. */
#define BPF_F_PSEUDO_HDR (1ULL << 4)
#define BPF_F_MARK_MANGLED_0 (1ULL << 5)
#define BPF_F_MARK_ENFORCE (1ULL << 6)

/* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
#define BPF_F_INGRESS (1ULL << 0)
Expand Down
64 changes: 45 additions & 19 deletions kernel/bpf/verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -1566,22 +1566,54 @@ static int evaluate_reg_imm_alu(struct bpf_verifier_env *env,
struct bpf_reg_state *dst_reg = &regs[insn->dst_reg];
struct bpf_reg_state *src_reg = &regs[insn->src_reg];
u8 opcode = BPF_OP(insn->code);
u64 dst_imm = dst_reg->imm;

/* dst_reg->type == CONST_IMM here, simulate execution of 'add'/'or'
* insn. Don't care about overflow or negative values, just add them
/* dst_reg->type == CONST_IMM here. Simulate execution of insns
* containing ALU ops. Don't care about overflow or negative
* values, just add/sub/... them; registers are in u64.
*/
if (opcode == BPF_ADD && BPF_SRC(insn->code) == BPF_K)
dst_reg->imm += insn->imm;
else if (opcode == BPF_ADD && BPF_SRC(insn->code) == BPF_X &&
src_reg->type == CONST_IMM)
dst_reg->imm += src_reg->imm;
else if (opcode == BPF_OR && BPF_SRC(insn->code) == BPF_K)
dst_reg->imm |= insn->imm;
else if (opcode == BPF_OR && BPF_SRC(insn->code) == BPF_X &&
src_reg->type == CONST_IMM)
dst_reg->imm |= src_reg->imm;
else
if (opcode == BPF_ADD && BPF_SRC(insn->code) == BPF_K) {
dst_imm += insn->imm;
} else if (opcode == BPF_ADD && BPF_SRC(insn->code) == BPF_X &&
src_reg->type == CONST_IMM) {
dst_imm += src_reg->imm;
} else if (opcode == BPF_SUB && BPF_SRC(insn->code) == BPF_K) {
dst_imm -= insn->imm;
} else if (opcode == BPF_SUB && BPF_SRC(insn->code) == BPF_X &&
src_reg->type == CONST_IMM) {
dst_imm -= src_reg->imm;
} else if (opcode == BPF_MUL && BPF_SRC(insn->code) == BPF_K) {
dst_imm *= insn->imm;
} else if (opcode == BPF_MUL && BPF_SRC(insn->code) == BPF_X &&
src_reg->type == CONST_IMM) {
dst_imm *= src_reg->imm;
} else if (opcode == BPF_OR && BPF_SRC(insn->code) == BPF_K) {
dst_imm |= insn->imm;
} else if (opcode == BPF_OR && BPF_SRC(insn->code) == BPF_X &&
src_reg->type == CONST_IMM) {
dst_imm |= src_reg->imm;
} else if (opcode == BPF_AND && BPF_SRC(insn->code) == BPF_K) {
dst_imm &= insn->imm;
} else if (opcode == BPF_AND && BPF_SRC(insn->code) == BPF_X &&
src_reg->type == CONST_IMM) {
dst_imm &= src_reg->imm;
} else if (opcode == BPF_RSH && BPF_SRC(insn->code) == BPF_K) {
dst_imm >>= insn->imm;
} else if (opcode == BPF_RSH && BPF_SRC(insn->code) == BPF_X &&
src_reg->type == CONST_IMM) {
dst_imm >>= src_reg->imm;
} else if (opcode == BPF_LSH && BPF_SRC(insn->code) == BPF_K) {
dst_imm <<= insn->imm;
} else if (opcode == BPF_LSH && BPF_SRC(insn->code) == BPF_X &&
src_reg->type == CONST_IMM) {
dst_imm <<= src_reg->imm;
} else {
mark_reg_unknown_value(regs, insn->dst_reg);
goto out;
}

dst_reg->imm = dst_imm;
out:
return 0;
}

Expand Down Expand Up @@ -2225,14 +2257,8 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn)
return err;

if (insn->src_reg == 0) {
/* generic move 64-bit immediate into a register,
* only analyzer needs to collect the ld_imm value.
*/
u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm;

if (!env->analyzer_ops)
return 0;

regs[insn->dst_reg].type = CONST_IMM;
regs[insn->dst_reg].imm = imm;
return 0;
Expand Down
63 changes: 32 additions & 31 deletions net/core/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -1522,18 +1522,19 @@ BPF_CALL_5(bpf_l4_csum_replace, struct sk_buff *, skb, u32, offset,
{
bool is_pseudo = flags & BPF_F_PSEUDO_HDR;
bool is_mmzero = flags & BPF_F_MARK_MANGLED_0;
bool do_mforce = flags & BPF_F_MARK_ENFORCE;
__sum16 *ptr;

if (unlikely(flags & ~(BPF_F_MARK_MANGLED_0 | BPF_F_PSEUDO_HDR |
BPF_F_HDR_FIELD_MASK)))
if (unlikely(flags & ~(BPF_F_MARK_MANGLED_0 | BPF_F_MARK_ENFORCE |
BPF_F_PSEUDO_HDR | BPF_F_HDR_FIELD_MASK)))
return -EINVAL;
if (unlikely(offset > 0xffff || offset & 1))
return -EFAULT;
if (unlikely(bpf_try_make_writable(skb, offset + sizeof(*ptr))))
return -EFAULT;

ptr = (__sum16 *)(skb->data + offset);
if (is_mmzero && !*ptr)
if (is_mmzero && !do_mforce && !*ptr)
return 0;

switch (flags & BPF_F_HDR_FIELD_MASK) {
Expand Down Expand Up @@ -2598,7 +2599,7 @@ static const struct bpf_func_proto bpf_xdp_event_output_proto = {
};

static const struct bpf_func_proto *
sk_filter_func_proto(enum bpf_func_id func_id)
bpf_base_func_proto(enum bpf_func_id func_id)
{
switch (func_id) {
case BPF_FUNC_map_lookup_elem:
Expand All @@ -2625,6 +2626,17 @@ sk_filter_func_proto(enum bpf_func_id func_id)
}
}

static const struct bpf_func_proto *
sk_filter_func_proto(enum bpf_func_id func_id)
{
switch (func_id) {
case BPF_FUNC_skb_load_bytes:
return &bpf_skb_load_bytes_proto;
default:
return bpf_base_func_proto(func_id);
}
}

static const struct bpf_func_proto *
tc_cls_act_func_proto(enum bpf_func_id func_id)
{
Expand Down Expand Up @@ -2680,7 +2692,7 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
case BPF_FUNC_skb_under_cgroup:
return &bpf_skb_under_cgroup_proto;
default:
return sk_filter_func_proto(func_id);
return bpf_base_func_proto(func_id);
}
}

Expand All @@ -2695,7 +2707,7 @@ xdp_func_proto(enum bpf_func_id func_id)
case BPF_FUNC_xdp_adjust_head:
return &bpf_xdp_adjust_head_proto;
default:
return sk_filter_func_proto(func_id);
return bpf_base_func_proto(func_id);
}
}

Expand All @@ -2706,7 +2718,7 @@ cg_skb_func_proto(enum bpf_func_id func_id)
case BPF_FUNC_skb_load_bytes:
return &bpf_skb_load_bytes_proto;
default:
return sk_filter_func_proto(func_id);
return bpf_base_func_proto(func_id);
}
}

Expand All @@ -2733,7 +2745,7 @@ lwt_inout_func_proto(enum bpf_func_id func_id)
case BPF_FUNC_skb_under_cgroup:
return &bpf_skb_under_cgroup_proto;
default:
return sk_filter_func_proto(func_id);
return bpf_base_func_proto(func_id);
}
}

Expand Down Expand Up @@ -2784,19 +2796,8 @@ static bool __is_valid_access(int off, int size)
switch (off) {
case offsetof(struct __sk_buff, cb[0]) ...
offsetof(struct __sk_buff, cb[4]) + sizeof(__u32) - 1:
if (size == sizeof(__u16) &&
off > offsetof(struct __sk_buff, cb[4]) + sizeof(__u16))
return false;
if (size == sizeof(__u32) &&
off > offsetof(struct __sk_buff, cb[4]))
return false;
if (size == sizeof(__u64) &&
off > offsetof(struct __sk_buff, cb[2]))
return false;
if (size != sizeof(__u8) &&
size != sizeof(__u16) &&
size != sizeof(__u32) &&
size != sizeof(__u64))
if (off + size >
offsetof(struct __sk_buff, cb[4]) + sizeof(__u32))
return false;
break;
default:
Expand Down Expand Up @@ -2994,10 +2995,10 @@ void bpf_warn_invalid_xdp_action(u32 act)
}
EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_action);

static u32 sk_filter_convert_ctx_access(enum bpf_access_type type,
const struct bpf_insn *si,
struct bpf_insn *insn_buf,
struct bpf_prog *prog)
static u32 bpf_convert_ctx_access(enum bpf_access_type type,
const struct bpf_insn *si,
struct bpf_insn *insn_buf,
struct bpf_prog *prog)
{
struct bpf_insn *insn = insn_buf;
int off;
Expand Down Expand Up @@ -3221,7 +3222,7 @@ static u32 tc_cls_act_convert_ctx_access(enum bpf_access_type type,
offsetof(struct net_device, ifindex));
break;
default:
return sk_filter_convert_ctx_access(type, si, insn_buf, prog);
return bpf_convert_ctx_access(type, si, insn_buf, prog);
}

return insn - insn_buf;
Expand Down Expand Up @@ -3253,7 +3254,7 @@ static u32 xdp_convert_ctx_access(enum bpf_access_type type,
static const struct bpf_verifier_ops sk_filter_ops = {
.get_func_proto = sk_filter_func_proto,
.is_valid_access = sk_filter_is_valid_access,
.convert_ctx_access = sk_filter_convert_ctx_access,
.convert_ctx_access = bpf_convert_ctx_access,
};

static const struct bpf_verifier_ops tc_cls_act_ops = {
Expand All @@ -3272,24 +3273,24 @@ static const struct bpf_verifier_ops xdp_ops = {
static const struct bpf_verifier_ops cg_skb_ops = {
.get_func_proto = cg_skb_func_proto,
.is_valid_access = sk_filter_is_valid_access,
.convert_ctx_access = sk_filter_convert_ctx_access,
.convert_ctx_access = bpf_convert_ctx_access,
};

static const struct bpf_verifier_ops lwt_inout_ops = {
.get_func_proto = lwt_inout_func_proto,
.is_valid_access = lwt_is_valid_access,
.convert_ctx_access = sk_filter_convert_ctx_access,
.convert_ctx_access = bpf_convert_ctx_access,
};

static const struct bpf_verifier_ops lwt_xmit_ops = {
.get_func_proto = lwt_xmit_func_proto,
.is_valid_access = lwt_is_valid_access,
.convert_ctx_access = sk_filter_convert_ctx_access,
.convert_ctx_access = bpf_convert_ctx_access,
.gen_prologue = tc_cls_act_prologue,
};

static const struct bpf_verifier_ops cg_sock_ops = {
.get_func_proto = sk_filter_func_proto,
.get_func_proto = bpf_base_func_proto,
.is_valid_access = sock_filter_is_valid_access,
.convert_ctx_access = sock_filter_convert_ctx_access,
};
Expand Down
4 changes: 2 additions & 2 deletions tools/testing/selftests/bpf/Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
CFLAGS += -Wall -O2 -I../../../../usr/include

test_objs = test_verifier test_maps test_lru_map test_lpm_map
test_objs = test_verifier test_tag test_maps test_lru_map test_lpm_map

TEST_PROGS := test_verifier test_maps test_lru_map test_lpm_map test_kmod.sh
TEST_PROGS := $(test_objs) test_kmod.sh
TEST_FILES := $(test_objs)

all: $(test_objs)
Expand Down
Loading

0 comments on commit bef4e17

Please sign in to comment.