|
Gary Lin |
3a7ed0 |
From: Daniel Borkmann <daniel@iogearbox.net>
|
|
Gary Lin |
3a7ed0 |
Date: Thu, 3 Jan 2019 00:58:27 +0100
|
|
Gary Lin |
3a7ed0 |
Subject: bpf: move {prev_,}insn_idx into verifier env
|
|
Gary Lin |
3a7ed0 |
Patch-mainline: v5.0-rc1
|
|
Gary Lin |
3a7ed0 |
Git-commit: c08435ec7f2bc8f4109401f696fd55159b4b40cb
|
|
Gary Lin |
e503a7 |
References: bsc#1068032 CVE-2017-5753 bsc#1124055 CVE-2019-7308
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
Move prev_insn_idx and insn_idx from the do_check() function into
|
|
Gary Lin |
3a7ed0 |
the verifier environment, so they can be read inside the various
|
|
Gary Lin |
3a7ed0 |
helper functions for handling the instructions. It's easier to put
|
|
Gary Lin |
3a7ed0 |
this into the environment rather than changing all call-sites only
|
|
Gary Lin |
3a7ed0 |
to pass it along. insn_idx is useful in particular since this later
|
|
Gary Lin |
3a7ed0 |
on allows to hold state in env->insn_aux_data[env->insn_idx].
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
|
|
Gary Lin |
3a7ed0 |
Acked-by: Alexei Starovoitov <ast@kernel.org>
|
|
Gary Lin |
3a7ed0 |
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
|
|
Gary Lin |
3a7ed0 |
Acked-by: Gary Lin <glin@suse.com>
|
|
Gary Lin |
3a7ed0 |
---
|
|
Gary Lin |
3a7ed0 |
include/linux/bpf_verifier.h | 2 +
|
|
Gary Lin |
3a7ed0 |
kernel/bpf/verifier.c | 65 +++++++++++++++++++++----------------------
|
|
Gary Lin |
3a7ed0 |
2 files changed, 34 insertions(+), 33 deletions(-)
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
--- a/include/linux/bpf_verifier.h
|
|
Gary Lin |
3a7ed0 |
+++ b/include/linux/bpf_verifier.h
|
|
Gary Lin |
3a7ed0 |
@@ -149,6 +149,8 @@ struct bpf_ext_analyzer_ops {
|
|
Gary Lin |
3a7ed0 |
* one verifier_env per bpf_check() call
|
|
Gary Lin |
3a7ed0 |
*/
|
|
Gary Lin |
3a7ed0 |
struct bpf_verifier_env {
|
|
Gary Lin |
3a7ed0 |
+ u32 insn_idx;
|
|
Gary Lin |
3a7ed0 |
+ u32 prev_insn_idx;
|
|
Gary Lin |
3a7ed0 |
struct bpf_prog *prog; /* eBPF program being verified */
|
|
Gary Lin |
3a7ed0 |
const struct bpf_verifier_ops *ops;
|
|
Gary Lin |
3a7ed0 |
struct bpf_verifier_stack_elem *head; /* stack of verifier states to be processed */
|
|
Gary Lin |
3a7ed0 |
--- a/kernel/bpf/verifier.c
|
|
Gary Lin |
3a7ed0 |
+++ b/kernel/bpf/verifier.c
|
|
Gary Lin |
3a7ed0 |
@@ -3751,7 +3751,6 @@ static int do_check(struct bpf_verifier_
|
|
Gary Lin |
3a7ed0 |
struct bpf_insn *insns = env->prog->insnsi;
|
|
Gary Lin |
3a7ed0 |
struct bpf_reg_state *regs;
|
|
Gary Lin |
3a7ed0 |
int insn_cnt = env->prog->len;
|
|
Gary Lin |
3a7ed0 |
- int insn_idx, prev_insn_idx = 0;
|
|
Gary Lin |
3a7ed0 |
int insn_processed = 0;
|
|
Gary Lin |
3a7ed0 |
bool do_print_state = false;
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
@@ -3761,19 +3760,18 @@ static int do_check(struct bpf_verifier_
|
|
Gary Lin |
3a7ed0 |
env->cur_state = state;
|
|
Gary Lin |
3a7ed0 |
init_reg_state(env, state->regs);
|
|
Gary Lin |
3a7ed0 |
state->parent = NULL;
|
|
Gary Lin |
3a7ed0 |
- insn_idx = 0;
|
|
Gary Lin |
3a7ed0 |
for (;;) {
|
|
Gary Lin |
3a7ed0 |
struct bpf_insn *insn;
|
|
Gary Lin |
3a7ed0 |
u8 class;
|
|
Gary Lin |
3a7ed0 |
int err;
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
- if (insn_idx >= insn_cnt) {
|
|
Gary Lin |
3a7ed0 |
+ if (env->insn_idx >= insn_cnt) {
|
|
Gary Lin |
3a7ed0 |
verbose(env, "invalid insn idx %d insn_cnt %d\n",
|
|
Gary Lin |
3a7ed0 |
- insn_idx, insn_cnt);
|
|
Gary Lin |
3a7ed0 |
+ env->insn_idx, insn_cnt);
|
|
Gary Lin |
3a7ed0 |
return -EFAULT;
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
- insn = &insns[insn_idx];
|
|
Gary Lin |
3a7ed0 |
+ insn = &insns[env->insn_idx];
|
|
Gary Lin |
3a7ed0 |
class = BPF_CLASS(insn->code);
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
if (++insn_processed > BPF_COMPLEXITY_LIMIT_INSNS) {
|
|
Gary Lin |
3a7ed0 |
@@ -3783,7 +3781,7 @@ static int do_check(struct bpf_verifier_
|
|
Gary Lin |
3a7ed0 |
return -E2BIG;
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
- err = is_state_visited(env, insn_idx);
|
|
Gary Lin |
3a7ed0 |
+ err = is_state_visited(env, env->insn_idx);
|
|
Gary Lin |
3a7ed0 |
if (err < 0)
|
|
Gary Lin |
3a7ed0 |
return err;
|
|
Gary Lin |
3a7ed0 |
if (err == 1) {
|
|
Gary Lin |
3a7ed0 |
@@ -3791,9 +3789,9 @@ static int do_check(struct bpf_verifier_
|
|
Gary Lin |
3a7ed0 |
if (env->log.level) {
|
|
Gary Lin |
3a7ed0 |
if (do_print_state)
|
|
Gary Lin |
3a7ed0 |
verbose(env, "\nfrom %d to %d: safe\n",
|
|
Gary Lin |
3a7ed0 |
- prev_insn_idx, insn_idx);
|
|
Gary Lin |
3a7ed0 |
+ env->prev_insn_idx, env->insn_idx);
|
|
Gary Lin |
3a7ed0 |
else
|
|
Gary Lin |
3a7ed0 |
- verbose(env, "%d: safe\n", insn_idx);
|
|
Gary Lin |
3a7ed0 |
+ verbose(env, "%d: safe\n", env->insn_idx);
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
goto process_bpf_exit;
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
@@ -3803,26 +3801,26 @@ static int do_check(struct bpf_verifier_
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
if (env->log.level > 1 || (env->log.level && do_print_state)) {
|
|
Gary Lin |
3a7ed0 |
if (env->log.level > 1)
|
|
Gary Lin |
3a7ed0 |
- verbose(env, "%d:", insn_idx);
|
|
Gary Lin |
3a7ed0 |
+ verbose(env, "%d:", env->insn_idx);
|
|
Gary Lin |
3a7ed0 |
else
|
|
Gary Lin |
3a7ed0 |
verbose(env, "\nfrom %d to %d:",
|
|
Gary Lin |
3a7ed0 |
- prev_insn_idx, insn_idx);
|
|
Gary Lin |
3a7ed0 |
+ env->prev_insn_idx, env->insn_idx);
|
|
Gary Lin |
3a7ed0 |
print_verifier_state(env, state);
|
|
Gary Lin |
3a7ed0 |
do_print_state = false;
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
if (env->log.level) {
|
|
Gary Lin |
3a7ed0 |
- verbose(env, "%d: ", insn_idx);
|
|
Gary Lin |
3a7ed0 |
+ verbose(env, "%d: ", env->insn_idx);
|
|
Gary Lin |
3a7ed0 |
print_bpf_insn(verbose, env, insn,
|
|
Gary Lin |
3a7ed0 |
env->allow_ptr_leaks);
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
- err = ext_analyzer_insn_hook(env, insn_idx, prev_insn_idx);
|
|
Gary Lin |
3a7ed0 |
+ err = ext_analyzer_insn_hook(env, env->insn_idx, env->prev_insn_idx);
|
|
Gary Lin |
3a7ed0 |
if (err)
|
|
Gary Lin |
3a7ed0 |
return err;
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
regs = cur_regs(env);
|
|
Gary Lin |
3a7ed0 |
- env->insn_aux_data[insn_idx].seen = true;
|
|
Gary Lin |
3a7ed0 |
+ env->insn_aux_data[env->insn_idx].seen = true;
|
|
Gary Lin |
3a7ed0 |
if (class == BPF_ALU || class == BPF_ALU64) {
|
|
Gary Lin |
3a7ed0 |
err = check_alu_op(env, insn);
|
|
Gary Lin |
3a7ed0 |
if (err)
|
|
Gary Lin |
3a7ed0 |
@@ -3847,13 +3845,13 @@ static int do_check(struct bpf_verifier_
|
|
Gary Lin |
3a7ed0 |
/* check that memory (src_reg + off) is readable,
|
|
Gary Lin |
3a7ed0 |
* the state of dst_reg will be updated by this func
|
|
Gary Lin |
3a7ed0 |
*/
|
|
Gary Lin |
3a7ed0 |
- err = check_mem_access(env, insn_idx, insn->src_reg, insn->off,
|
|
Gary Lin |
3a7ed0 |
- BPF_SIZE(insn->code), BPF_READ,
|
|
Gary Lin |
3a7ed0 |
- insn->dst_reg, false);
|
|
Gary Lin |
3a7ed0 |
+ err = check_mem_access(env, env->insn_idx, insn->src_reg,
|
|
Gary Lin |
3a7ed0 |
+ insn->off, BPF_SIZE(insn->code),
|
|
Gary Lin |
3a7ed0 |
+ BPF_READ, insn->dst_reg, false);
|
|
Gary Lin |
3a7ed0 |
if (err)
|
|
Gary Lin |
3a7ed0 |
return err;
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
- prev_src_type = &env->insn_aux_data[insn_idx].ptr_type;
|
|
Gary Lin |
3a7ed0 |
+ prev_src_type = &env->insn_aux_data[env->insn_idx].ptr_type;
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
if (*prev_src_type == NOT_INIT) {
|
|
Gary Lin |
3a7ed0 |
/* saw a valid insn
|
|
Gary Lin |
3a7ed0 |
@@ -3880,10 +3878,10 @@ static int do_check(struct bpf_verifier_
|
|
Gary Lin |
3a7ed0 |
enum bpf_reg_type *prev_dst_type, dst_reg_type;
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
if (BPF_MODE(insn->code) == BPF_XADD) {
|
|
Gary Lin |
3a7ed0 |
- err = check_xadd(env, insn_idx, insn);
|
|
Gary Lin |
3a7ed0 |
+ err = check_xadd(env, env->insn_idx, insn);
|
|
Gary Lin |
3a7ed0 |
if (err)
|
|
Gary Lin |
3a7ed0 |
return err;
|
|
Gary Lin |
3a7ed0 |
- insn_idx++;
|
|
Gary Lin |
3a7ed0 |
+ env->insn_idx++;
|
|
Gary Lin |
3a7ed0 |
continue;
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
@@ -3899,13 +3897,13 @@ static int do_check(struct bpf_verifier_
|
|
Gary Lin |
3a7ed0 |
dst_reg_type = regs[insn->dst_reg].type;
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
/* check that memory (dst_reg + off) is writeable */
|
|
Gary Lin |
3a7ed0 |
- err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
|
|
Gary Lin |
3a7ed0 |
- BPF_SIZE(insn->code), BPF_WRITE,
|
|
Gary Lin |
3a7ed0 |
- insn->src_reg, false);
|
|
Gary Lin |
3a7ed0 |
+ err = check_mem_access(env, env->insn_idx, insn->dst_reg,
|
|
Gary Lin |
3a7ed0 |
+ insn->off, BPF_SIZE(insn->code),
|
|
Gary Lin |
3a7ed0 |
+ BPF_WRITE, insn->src_reg, false);
|
|
Gary Lin |
3a7ed0 |
if (err)
|
|
Gary Lin |
3a7ed0 |
return err;
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
- prev_dst_type = &env->insn_aux_data[insn_idx].ptr_type;
|
|
Gary Lin |
3a7ed0 |
+ prev_dst_type = &env->insn_aux_data[env->insn_idx].ptr_type;
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
if (*prev_dst_type == NOT_INIT) {
|
|
Gary Lin |
3a7ed0 |
*prev_dst_type = dst_reg_type;
|
|
Gary Lin |
3a7ed0 |
@@ -3934,9 +3932,9 @@ static int do_check(struct bpf_verifier_
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
/* check that memory (dst_reg + off) is writeable */
|
|
Gary Lin |
3a7ed0 |
- err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
|
|
Gary Lin |
3a7ed0 |
- BPF_SIZE(insn->code), BPF_WRITE,
|
|
Gary Lin |
3a7ed0 |
- -1, false);
|
|
Gary Lin |
3a7ed0 |
+ err = check_mem_access(env, env->insn_idx, insn->dst_reg,
|
|
Gary Lin |
3a7ed0 |
+ insn->off, BPF_SIZE(insn->code),
|
|
Gary Lin |
3a7ed0 |
+ BPF_WRITE, -1, false);
|
|
Gary Lin |
3a7ed0 |
if (err)
|
|
Gary Lin |
3a7ed0 |
return err;
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
@@ -3952,7 +3950,7 @@ static int do_check(struct bpf_verifier_
|
|
Gary Lin |
3a7ed0 |
return -EINVAL;
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
- err = check_call(env, insn->imm, insn_idx);
|
|
Gary Lin |
3a7ed0 |
+ err = check_call(env, insn->imm, env->insn_idx);
|
|
Gary Lin |
3a7ed0 |
if (err)
|
|
Gary Lin |
3a7ed0 |
return err;
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
@@ -3965,7 +3963,7 @@ static int do_check(struct bpf_verifier_
|
|
Gary Lin |
3a7ed0 |
return -EINVAL;
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
- insn_idx += insn->off + 1;
|
|
Gary Lin |
3a7ed0 |
+ env->insn_idx += insn->off + 1;
|
|
Gary Lin |
3a7ed0 |
continue;
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
} else if (opcode == BPF_EXIT) {
|
|
Gary Lin |
3a7ed0 |
@@ -3993,7 +3991,8 @@ static int do_check(struct bpf_verifier_
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
process_bpf_exit:
|
|
Gary Lin |
3a7ed0 |
- err = pop_stack(env, &prev_insn_idx, &insn_idx);
|
|
Gary Lin |
3a7ed0 |
+ err = pop_stack(env, &env->prev_insn_idx,
|
|
Gary Lin |
3a7ed0 |
+ &env->insn_idx);
|
|
Gary Lin |
3a7ed0 |
if (err < 0) {
|
|
Gary Lin |
3a7ed0 |
if (err != -ENOENT)
|
|
Gary Lin |
3a7ed0 |
return err;
|
|
Gary Lin |
3a7ed0 |
@@ -4003,7 +4002,7 @@ process_bpf_exit:
|
|
Gary Lin |
3a7ed0 |
continue;
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
} else {
|
|
Gary Lin |
3a7ed0 |
- err = check_cond_jmp_op(env, insn, &insn_idx);
|
|
Gary Lin |
3a7ed0 |
+ err = check_cond_jmp_op(env, insn, &env->insn_idx);
|
|
Gary Lin |
3a7ed0 |
if (err)
|
|
Gary Lin |
3a7ed0 |
return err;
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
@@ -4020,8 +4019,8 @@ process_bpf_exit:
|
|
Gary Lin |
3a7ed0 |
if (err)
|
|
Gary Lin |
3a7ed0 |
return err;
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
- insn_idx++;
|
|
Gary Lin |
3a7ed0 |
- env->insn_aux_data[insn_idx].seen = true;
|
|
Gary Lin |
3a7ed0 |
+ env->insn_idx++;
|
|
Gary Lin |
3a7ed0 |
+ env->insn_aux_data[env->insn_idx].seen = true;
|
|
Gary Lin |
3a7ed0 |
} else {
|
|
Gary Lin |
3a7ed0 |
verbose(env, "invalid BPF_LD mode\n");
|
|
Gary Lin |
3a7ed0 |
return -EINVAL;
|
|
Gary Lin |
3a7ed0 |
@@ -4031,7 +4030,7 @@ process_bpf_exit:
|
|
Gary Lin |
3a7ed0 |
return -EINVAL;
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
- insn_idx++;
|
|
Gary Lin |
3a7ed0 |
+ env->insn_idx++;
|
|
Gary Lin |
3a7ed0 |
}
|
|
Gary Lin |
3a7ed0 |
|
|
Gary Lin |
3a7ed0 |
verbose(env, "processed %d insns, stack depth %d\n", insn_processed,
|