Commit 0989bd03 authored by David S. Miller's avatar David S. Miller

Merge branch 'bpf-map_value_adj-reg-types-fixes'

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: default avatarDavid S. Miller <davem@davemloft.net>
parents d5b07ccc 02ea80b1
...@@ -765,38 +765,56 @@ static bool is_pointer_value(struct bpf_verifier_env *env, int regno) ...@@ -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, static int check_pkt_ptr_alignment(const struct bpf_reg_state *reg,
struct bpf_reg_state *reg, int off, int size) 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) { 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; return -EACCES;
} }
/* skb->data is NET_IP_ALIGN-ed */ /* skb->data is NET_IP_ALIGN-ed */
if (reg->type == PTR_TO_PACKET && if ((NET_IP_ALIGN + reg->off + off) % size != 0) {
(NET_IP_ALIGN + reg->off + off) % size != 0) {
verbose("misaligned packet access off %d+%d+%d size %d\n", verbose("misaligned packet access off %d+%d+%d size %d\n",
NET_IP_ALIGN, reg->off, off, size); NET_IP_ALIGN, reg->off, off, size);
return -EACCES; return -EACCES;
} }
return 0; 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) /* 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==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 * if t==read, value_regno is a register which will receive the value from memory
...@@ -818,7 +836,7 @@ static int check_mem_access(struct bpf_verifier_env *env, u32 regno, int off, ...@@ -818,7 +836,7 @@ static int check_mem_access(struct bpf_verifier_env *env, u32 regno, int off,
if (size < 0) if (size < 0)
return size; return size;
err = check_ptr_alignment(env, reg, off, size); err = check_ptr_alignment(reg, off, size);
if (err) if (err)
return err; return err;
...@@ -1925,6 +1943,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) ...@@ -1925,6 +1943,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
* register as unknown. * register as unknown.
*/ */
if (env->allow_ptr_leaks && 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 ||
dst_reg->type == PTR_TO_MAP_VALUE_ADJ)) dst_reg->type == PTR_TO_MAP_VALUE_ADJ))
dst_reg->type = PTR_TO_MAP_VALUE_ADJ; dst_reg->type = PTR_TO_MAP_VALUE_ADJ;
......
...@@ -168,6 +168,16 @@ ...@@ -168,6 +168,16 @@
.off = OFF, \ .off = OFF, \
.imm = 0 }) .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 */ /* Memory store, *(uint *) (dst_reg + off16) = imm32 */
#define BPF_ST_MEM(SIZE, DST, OFF, IMM) \ #define BPF_ST_MEM(SIZE, DST, OFF, IMM) \
......
LIBDIR := ../../../lib LIBDIR := ../../../lib
BPFDIR := $(LIBDIR)/bpf 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 LDLIBS += -lcap
TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment