Commit 74b200d5 authored by David S. Miller's avatar David S. Miller

Merge branch 'BPF-range-marking-improvements-for-meta-data'

Daniel Borkmann says:

====================
BPF range marking improvements for meta data

The set contains improvements for direct packet access range
markings related to data_meta pointer and test cases for all
such access patterns that the verifier matches on.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 1495dc9f 634eab11
...@@ -2532,7 +2532,7 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *state, ...@@ -2532,7 +2532,7 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *state,
continue; continue;
reg = &state->stack[i].spilled_ptr; reg = &state->stack[i].spilled_ptr;
if (reg->type == type && reg->id == dst_reg->id) if (reg->type == type && reg->id == dst_reg->id)
reg->range = max_t(u16, reg->range, new_range); reg->range = max(reg->range, new_range);
} }
} }
...@@ -2787,6 +2787,99 @@ static void mark_map_regs(struct bpf_verifier_state *state, u32 regno, ...@@ -2787,6 +2787,99 @@ static void mark_map_regs(struct bpf_verifier_state *state, u32 regno,
} }
} }
static bool try_match_pkt_pointers(const struct bpf_insn *insn,
struct bpf_reg_state *dst_reg,
struct bpf_reg_state *src_reg,
struct bpf_verifier_state *this_branch,
struct bpf_verifier_state *other_branch)
{
if (BPF_SRC(insn->code) != BPF_X)
return false;
switch (BPF_OP(insn->code)) {
case BPF_JGT:
if ((dst_reg->type == PTR_TO_PACKET &&
src_reg->type == PTR_TO_PACKET_END) ||
(dst_reg->type == PTR_TO_PACKET_META &&
reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET))) {
/* pkt_data' > pkt_end, pkt_meta' > pkt_data */
find_good_pkt_pointers(this_branch, dst_reg,
dst_reg->type, false);
} else if ((dst_reg->type == PTR_TO_PACKET_END &&
src_reg->type == PTR_TO_PACKET) ||
(reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) &&
src_reg->type == PTR_TO_PACKET_META)) {
/* pkt_end > pkt_data', pkt_data > pkt_meta' */
find_good_pkt_pointers(other_branch, src_reg,
src_reg->type, true);
} else {
return false;
}
break;
case BPF_JLT:
if ((dst_reg->type == PTR_TO_PACKET &&
src_reg->type == PTR_TO_PACKET_END) ||
(dst_reg->type == PTR_TO_PACKET_META &&
reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET))) {
/* pkt_data' < pkt_end, pkt_meta' < pkt_data */
find_good_pkt_pointers(other_branch, dst_reg,
dst_reg->type, true);
} else if ((dst_reg->type == PTR_TO_PACKET_END &&
src_reg->type == PTR_TO_PACKET) ||
(reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) &&
src_reg->type == PTR_TO_PACKET_META)) {
/* pkt_end < pkt_data', pkt_data > pkt_meta' */
find_good_pkt_pointers(this_branch, src_reg,
src_reg->type, false);
} else {
return false;
}
break;
case BPF_JGE:
if ((dst_reg->type == PTR_TO_PACKET &&
src_reg->type == PTR_TO_PACKET_END) ||
(dst_reg->type == PTR_TO_PACKET_META &&
reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET))) {
/* pkt_data' >= pkt_end, pkt_meta' >= pkt_data */
find_good_pkt_pointers(this_branch, dst_reg,
dst_reg->type, true);
} else if ((dst_reg->type == PTR_TO_PACKET_END &&
src_reg->type == PTR_TO_PACKET) ||
(reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) &&
src_reg->type == PTR_TO_PACKET_META)) {
/* pkt_end >= pkt_data', pkt_data >= pkt_meta' */
find_good_pkt_pointers(other_branch, src_reg,
src_reg->type, false);
} else {
return false;
}
break;
case BPF_JLE:
if ((dst_reg->type == PTR_TO_PACKET &&
src_reg->type == PTR_TO_PACKET_END) ||
(dst_reg->type == PTR_TO_PACKET_META &&
reg_is_init_pkt_pointer(src_reg, PTR_TO_PACKET))) {
/* pkt_data' <= pkt_end, pkt_meta' <= pkt_data */
find_good_pkt_pointers(other_branch, dst_reg,
dst_reg->type, false);
} else if ((dst_reg->type == PTR_TO_PACKET_END &&
src_reg->type == PTR_TO_PACKET) ||
(reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) &&
src_reg->type == PTR_TO_PACKET_META)) {
/* pkt_end <= pkt_data', pkt_data <= pkt_meta' */
find_good_pkt_pointers(this_branch, src_reg,
src_reg->type, true);
} else {
return false;
}
break;
default:
return false;
}
return true;
}
static int check_cond_jmp_op(struct bpf_verifier_env *env, static int check_cond_jmp_op(struct bpf_verifier_env *env,
struct bpf_insn *insn, int *insn_idx) struct bpf_insn *insn, int *insn_idx)
{ {
...@@ -2893,75 +2986,9 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, ...@@ -2893,75 +2986,9 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
*/ */
mark_map_regs(this_branch, insn->dst_reg, opcode == BPF_JNE); mark_map_regs(this_branch, insn->dst_reg, opcode == BPF_JNE);
mark_map_regs(other_branch, insn->dst_reg, opcode == BPF_JEQ); mark_map_regs(other_branch, insn->dst_reg, opcode == BPF_JEQ);
} else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT && } else if (!try_match_pkt_pointers(insn, dst_reg, &regs[insn->src_reg],
dst_reg->type == PTR_TO_PACKET && this_branch, other_branch) &&
regs[insn->src_reg].type == PTR_TO_PACKET_END) { is_pointer_value(env, insn->dst_reg)) {
/* pkt_data' > pkt_end */
find_good_pkt_pointers(this_branch, dst_reg,
PTR_TO_PACKET, false);
} else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT &&
dst_reg->type == PTR_TO_PACKET_END &&
regs[insn->src_reg].type == PTR_TO_PACKET) {
/* pkt_end > pkt_data' */
find_good_pkt_pointers(other_branch, &regs[insn->src_reg],
PTR_TO_PACKET, true);
} else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLT &&
dst_reg->type == PTR_TO_PACKET &&
regs[insn->src_reg].type == PTR_TO_PACKET_END) {
/* pkt_data' < pkt_end */
find_good_pkt_pointers(other_branch, dst_reg, PTR_TO_PACKET,
true);
} else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLT &&
dst_reg->type == PTR_TO_PACKET_END &&
regs[insn->src_reg].type == PTR_TO_PACKET) {
/* pkt_end < pkt_data' */
find_good_pkt_pointers(this_branch, &regs[insn->src_reg],
PTR_TO_PACKET, false);
} else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGE &&
dst_reg->type == PTR_TO_PACKET &&
regs[insn->src_reg].type == PTR_TO_PACKET_END) {
/* pkt_data' >= pkt_end */
find_good_pkt_pointers(this_branch, dst_reg,
PTR_TO_PACKET, true);
} else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGE &&
dst_reg->type == PTR_TO_PACKET_END &&
regs[insn->src_reg].type == PTR_TO_PACKET) {
/* pkt_end >= pkt_data' */
find_good_pkt_pointers(other_branch, &regs[insn->src_reg],
PTR_TO_PACKET, false);
} else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLE &&
dst_reg->type == PTR_TO_PACKET &&
regs[insn->src_reg].type == PTR_TO_PACKET_END) {
/* pkt_data' <= pkt_end */
find_good_pkt_pointers(other_branch, dst_reg,
PTR_TO_PACKET, false);
} else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLE &&
dst_reg->type == PTR_TO_PACKET_END &&
regs[insn->src_reg].type == PTR_TO_PACKET) {
/* pkt_end <= pkt_data' */
find_good_pkt_pointers(this_branch, &regs[insn->src_reg],
PTR_TO_PACKET, true);
} else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGT &&
dst_reg->type == PTR_TO_PACKET_META &&
reg_is_init_pkt_pointer(&regs[insn->src_reg], PTR_TO_PACKET)) {
find_good_pkt_pointers(this_branch, dst_reg,
PTR_TO_PACKET_META, false);
} else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLT &&
dst_reg->type == PTR_TO_PACKET_META &&
reg_is_init_pkt_pointer(&regs[insn->src_reg], PTR_TO_PACKET)) {
find_good_pkt_pointers(other_branch, dst_reg,
PTR_TO_PACKET_META, false);
} else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JGE &&
reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) &&
regs[insn->src_reg].type == PTR_TO_PACKET_META) {
find_good_pkt_pointers(other_branch, &regs[insn->src_reg],
PTR_TO_PACKET_META, false);
} else if (BPF_SRC(insn->code) == BPF_X && opcode == BPF_JLE &&
reg_is_init_pkt_pointer(dst_reg, PTR_TO_PACKET) &&
regs[insn->src_reg].type == PTR_TO_PACKET_META) {
find_good_pkt_pointers(this_branch, &regs[insn->src_reg],
PTR_TO_PACKET_META, false);
} else if (is_pointer_value(env, insn->dst_reg)) {
verbose(env, "R%d pointer comparison prohibited\n", verbose(env, "R%d pointer comparison prohibited\n",
insn->dst_reg); insn->dst_reg);
return -EACCES; return -EACCES;
......
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