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,