Skip to content

Commit

Permalink
Merge branch 'bpf-map_value_adj-reg-types-fixes'
Browse files Browse the repository at this point in the history
Daniel Borkmann says:

====================
BPF fixes on map_value_adj reg types

This set adds two fixes for map_value_adj register type in the
verifier and user space tests along with them for the BPF self
test suite. For details, please see individual patches.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Apr 1, 2017
2 parents d5b07cc + 02ea80b commit 0989bd0
Show file tree
Hide file tree
Showing 4 changed files with 322 additions and 26 deletions.
59 changes: 39 additions & 20 deletions kernel/bpf/verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -765,38 +765,56 @@ static bool is_pointer_value(struct bpf_verifier_env *env, int regno)
}
}

static int check_ptr_alignment(struct bpf_verifier_env *env,
struct bpf_reg_state *reg, int off, int size)
static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg,
int off, int size)
{
if (reg->type != PTR_TO_PACKET && reg->type != PTR_TO_MAP_VALUE_ADJ) {
if (off % size != 0) {
verbose("misaligned access off %d size %d\n",
off, size);
return -EACCES;
} else {
return 0;
}
}

if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
/* misaligned access to packet is ok on x86,arm,arm64 */
return 0;

if (reg->id && size != 1) {
verbose("Unknown packet alignment. Only byte-sized access allowed\n");
verbose("Unknown alignment. Only byte-sized access allowed in packet access.\n");
return -EACCES;
}

/* skb->data is NET_IP_ALIGN-ed */
if (reg->type == PTR_TO_PACKET &&
(NET_IP_ALIGN + reg->off + off) % size != 0) {
if ((NET_IP_ALIGN + reg->off + off) % size != 0) {
verbose("misaligned packet access off %d+%d+%d size %d\n",
NET_IP_ALIGN, reg->off, off, size);
return -EACCES;
}

return 0;
}

static int check_val_ptr_alignment(const struct bpf_reg_state *reg,
int size)
{
if (size != 1) {
verbose("Unknown alignment. Only byte-sized access allowed in value access.\n");
return -EACCES;
}

return 0;
}

static int check_ptr_alignment(const struct bpf_reg_state *reg,
int off, int size)
{
switch (reg->type) {
case PTR_TO_PACKET:
return IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ? 0 :
check_pkt_ptr_alignment(reg, off, size);
case PTR_TO_MAP_VALUE_ADJ:
return IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ? 0 :
check_val_ptr_alignment(reg, size);
default:
if (off % size != 0) {
verbose("misaligned access off %d size %d\n",
off, size);
return -EACCES;
}

return 0;
}
}

/* check whether memory at (regno + off) is accessible for t = (read | write)
* if t==write, value_regno is a register which value is stored into memory
* if t==read, value_regno is a register which will receive the value from memory
Expand All @@ -818,7 +836,7 @@ static int check_mem_access(struct bpf_verifier_env *env, u32 regno, int off,
if (size < 0)
return size;

err = check_ptr_alignment(env, reg, off, size);
err = check_ptr_alignment(reg, off, size);
if (err)
return err;

Expand Down Expand Up @@ -1925,6 +1943,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
* register as unknown.
*/
if (env->allow_ptr_leaks &&
BPF_CLASS(insn->code) == BPF_ALU64 && opcode == BPF_ADD &&
(dst_reg->type == PTR_TO_MAP_VALUE ||
dst_reg->type == PTR_TO_MAP_VALUE_ADJ))
dst_reg->type = PTR_TO_MAP_VALUE_ADJ;
Expand Down
10 changes: 10 additions & 0 deletions tools/include/linux/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,16 @@
.off = OFF, \
.imm = 0 })

/* Atomic memory add, *(uint *)(dst_reg + off16) += src_reg */

#define BPF_STX_XADD(SIZE, DST, SRC, OFF) \
((struct bpf_insn) { \
.code = BPF_STX | BPF_SIZE(SIZE) | BPF_XADD, \
.dst_reg = DST, \
.src_reg = SRC, \
.off = OFF, \
.imm = 0 })

/* Memory store, *(uint *) (dst_reg + off16) = imm32 */

#define BPF_ST_MEM(SIZE, DST, OFF, IMM) \
Expand Down
9 changes: 8 additions & 1 deletion tools/testing/selftests/bpf/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
LIBDIR := ../../../lib
BPFDIR := $(LIBDIR)/bpf
APIDIR := ../../../include/uapi
GENDIR := ../../../../include/generated
GENHDR := $(GENDIR)/autoconf.h

CFLAGS += -Wall -O2 -I../../../include/uapi -I$(LIBDIR)
ifneq ($(wildcard $(GENHDR)),)
GENFLAGS := -DHAVE_GENHDR
endif

CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS)
LDLIBS += -lcap

TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map
Expand Down
Loading

0 comments on commit 0989bd0

Please sign in to comment.