Jiri Slaby 6b3564
From: John Fastabend <john.fastabend@gmail.com>
Jiri Slaby 6b3564
Date: Sun, 2 Jul 2017 02:13:30 +0200
Jiri Slaby 6b3564
Subject: [PATCH] bpf, verifier: add additional patterns to
Jiri Slaby 6b3564
 evaluate_reg_imm_alu
Jiri Slaby 6b3564
References: bnc#1060662
Thomas Zimmermann 1d81d2
Patch-mainline: v4.12.10
Jiri Slaby 6b3564
Git-commit: 43188702b3d98d2792969a3377a30957f05695e6
Jiri Slaby 6b3564
Jiri Slaby 6b3564
[ Upstream commit 43188702b3d98d2792969a3377a30957f05695e6 ]
Jiri Slaby 6b3564
Jiri Slaby 6b3564
Currently the verifier does not track imm across alu operations when
Jiri Slaby 6b3564
the source register is of unknown type. This adds additional pattern
Jiri Slaby 6b3564
matching to catch this and track imm. We've seen LLVM generating this
Jiri Slaby 6b3564
pattern while working on cilium.
Jiri Slaby 6b3564
Jiri Slaby 6b3564
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
Jiri Slaby 6b3564
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Jiri Slaby 6b3564
Acked-by: Alexei Starovoitov <ast@kernel.org>
Jiri Slaby 6b3564
Signed-off-by: David S. Miller <davem@davemloft.net>
Jiri Slaby 6b3564
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Jiri Slaby 6b3564
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Jiri Slaby 6b3564
---
Jiri Slaby 6b3564
 kernel/bpf/verifier.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
Jiri Slaby 6b3564
 1 file changed, 62 insertions(+)
Jiri Slaby 6b3564
Jiri Slaby 6b3564
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
Jiri Slaby 6b3564
index a8a725697bed..03f8d02849be 100644
Jiri Slaby 6b3564
--- a/kernel/bpf/verifier.c
Jiri Slaby 6b3564
+++ b/kernel/bpf/verifier.c
Jiri Slaby 6b3564
@@ -1650,6 +1650,65 @@ static int evaluate_reg_alu(struct bpf_verifier_env *env, struct bpf_insn *insn)
Jiri Slaby 6b3564
 	return 0;
Jiri Slaby 6b3564
 }
Jiri Slaby 6b3564
 
Jiri Slaby 6b3564
+static int evaluate_reg_imm_alu_unknown(struct bpf_verifier_env *env,
Jiri Slaby 6b3564
+					struct bpf_insn *insn)
Jiri Slaby 6b3564
+{
Jiri Slaby 6b3564
+	struct bpf_reg_state *regs = env->cur_state.regs;
Jiri Slaby 6b3564
+	struct bpf_reg_state *dst_reg = &regs[insn->dst_reg];
Jiri Slaby 6b3564
+	struct bpf_reg_state *src_reg = &regs[insn->src_reg];
Jiri Slaby 6b3564
+	u8 opcode = BPF_OP(insn->code);
Jiri Slaby 6b3564
+	s64 imm_log2 = __ilog2_u64((long long)dst_reg->imm);
Jiri Slaby 6b3564
+
Jiri Slaby 6b3564
+	/* BPF_X code with src_reg->type UNKNOWN_VALUE here. */
Jiri Slaby 6b3564
+	if (src_reg->imm > 0 && dst_reg->imm) {
Jiri Slaby 6b3564
+		switch (opcode) {
Jiri Slaby 6b3564
+		case BPF_ADD:
Jiri Slaby 6b3564
+			/* dreg += sreg
Jiri Slaby 6b3564
+			 * where both have zero upper bits. Adding them
Jiri Slaby 6b3564
+			 * can only result making one more bit non-zero
Jiri Slaby 6b3564
+			 * in the larger value.
Jiri Slaby 6b3564
+			 * Ex. 0xffff (imm=48) + 1 (imm=63) = 0x10000 (imm=47)
Jiri Slaby 6b3564
+			 *     0xffff (imm=48) + 0xffff = 0x1fffe (imm=47)
Jiri Slaby 6b3564
+			 */
Jiri Slaby 6b3564
+			dst_reg->imm = min(src_reg->imm, 63 - imm_log2);
Jiri Slaby 6b3564
+			dst_reg->imm--;
Jiri Slaby 6b3564
+			break;
Jiri Slaby 6b3564
+		case BPF_AND:
Jiri Slaby 6b3564
+			/* dreg &= sreg
Jiri Slaby 6b3564
+			 * AND can not extend zero bits only shrink
Jiri Slaby 6b3564
+			 * Ex.  0x00..00ffffff
Jiri Slaby 6b3564
+			 *    & 0x0f..ffffffff
Jiri Slaby 6b3564
+			 *     ----------------
Jiri Slaby 6b3564
+			 *      0x00..00ffffff
Jiri Slaby 6b3564
+			 */
Jiri Slaby 6b3564
+			dst_reg->imm = max(src_reg->imm, 63 - imm_log2);
Jiri Slaby 6b3564
+			break;
Jiri Slaby 6b3564
+		case BPF_OR:
Jiri Slaby 6b3564
+			/* dreg |= sreg
Jiri Slaby 6b3564
+			 * OR can only extend zero bits
Jiri Slaby 6b3564
+			 * Ex.  0x00..00ffffff
Jiri Slaby 6b3564
+			 *    | 0x0f..ffffffff
Jiri Slaby 6b3564
+			 *     ----------------
Jiri Slaby 6b3564
+			 *      0x0f..00ffffff
Jiri Slaby 6b3564
+			 */
Jiri Slaby 6b3564
+			dst_reg->imm = min(src_reg->imm, 63 - imm_log2);
Jiri Slaby 6b3564
+			break;
Jiri Slaby 6b3564
+		case BPF_SUB:
Jiri Slaby 6b3564
+		case BPF_MUL:
Jiri Slaby 6b3564
+		case BPF_RSH:
Jiri Slaby 6b3564
+		case BPF_LSH:
Jiri Slaby 6b3564
+			/* These may be flushed out later */
Jiri Slaby 6b3564
+		default:
Jiri Slaby 6b3564
+			mark_reg_unknown_value(regs, insn->dst_reg);
Jiri Slaby 6b3564
+		}
Jiri Slaby 6b3564
+	} else {
Jiri Slaby 6b3564
+		mark_reg_unknown_value(regs, insn->dst_reg);
Jiri Slaby 6b3564
+	}
Jiri Slaby 6b3564
+
Jiri Slaby 6b3564
+	dst_reg->type = UNKNOWN_VALUE;
Jiri Slaby 6b3564
+	return 0;
Jiri Slaby 6b3564
+}
Jiri Slaby 6b3564
+
Jiri Slaby 6b3564
 static int evaluate_reg_imm_alu(struct bpf_verifier_env *env,
Jiri Slaby 6b3564
 				struct bpf_insn *insn)
Jiri Slaby 6b3564
 {
Jiri Slaby 6b3564
@@ -1659,6 +1718,9 @@ static int evaluate_reg_imm_alu(struct bpf_verifier_env *env,
Jiri Slaby 6b3564
 	u8 opcode = BPF_OP(insn->code);
Jiri Slaby 6b3564
 	u64 dst_imm = dst_reg->imm;
Jiri Slaby 6b3564
 
Jiri Slaby 6b3564
+	if (BPF_SRC(insn->code) == BPF_X && src_reg->type == UNKNOWN_VALUE)
Jiri Slaby 6b3564
+		return evaluate_reg_imm_alu_unknown(env, insn);
Jiri Slaby 6b3564
+
Jiri Slaby 6b3564
 	/* dst_reg->type == CONST_IMM here. Simulate execution of insns
Jiri Slaby 6b3564
 	 * containing ALU ops. Don't care about overflow or negative
Jiri Slaby 6b3564
 	 * values, just add/sub/... them; registers are in u64.
Jiri Slaby 6b3564
-- 
Jiri Slaby 6b3564
2.14.2
Jiri Slaby 6b3564