|
@@ -1657,6 +1657,65 @@ static int evaluate_reg_alu(struct bpf_verifier_env *env, struct bpf_insn *insn)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int evaluate_reg_imm_alu_unknown(struct bpf_verifier_env *env,
|
|
|
|
+ struct bpf_insn *insn)
|
|
|
|
+{
|
|
|
|
+ struct bpf_reg_state *regs = env->cur_state.regs;
|
|
|
|
+ struct bpf_reg_state *dst_reg = ®s[insn->dst_reg];
|
|
|
|
+ struct bpf_reg_state *src_reg = ®s[insn->src_reg];
|
|
|
|
+ u8 opcode = BPF_OP(insn->code);
|
|
|
|
+ s64 imm_log2 = __ilog2_u64((long long)dst_reg->imm);
|
|
|
|
+
|
|
|
|
+ /* BPF_X code with src_reg->type UNKNOWN_VALUE here. */
|
|
|
|
+ if (src_reg->imm > 0 && dst_reg->imm) {
|
|
|
|
+ switch (opcode) {
|
|
|
|
+ case BPF_ADD:
|
|
|
|
+ /* dreg += sreg
|
|
|
|
+ * where both have zero upper bits. Adding them
|
|
|
|
+ * can only result making one more bit non-zero
|
|
|
|
+ * in the larger value.
|
|
|
|
+ * Ex. 0xffff (imm=48) + 1 (imm=63) = 0x10000 (imm=47)
|
|
|
|
+ * 0xffff (imm=48) + 0xffff = 0x1fffe (imm=47)
|
|
|
|
+ */
|
|
|
|
+ dst_reg->imm = min(src_reg->imm, 63 - imm_log2);
|
|
|
|
+ dst_reg->imm--;
|
|
|
|
+ break;
|
|
|
|
+ case BPF_AND:
|
|
|
|
+ /* dreg &= sreg
|
|
|
|
+ * AND can not extend zero bits only shrink
|
|
|
|
+ * Ex. 0x00..00ffffff
|
|
|
|
+ * & 0x0f..ffffffff
|
|
|
|
+ * ----------------
|
|
|
|
+ * 0x00..00ffffff
|
|
|
|
+ */
|
|
|
|
+ dst_reg->imm = max(src_reg->imm, 63 - imm_log2);
|
|
|
|
+ break;
|
|
|
|
+ case BPF_OR:
|
|
|
|
+ /* dreg |= sreg
|
|
|
|
+ * OR can only extend zero bits
|
|
|
|
+ * Ex. 0x00..00ffffff
|
|
|
|
+ * | 0x0f..ffffffff
|
|
|
|
+ * ----------------
|
|
|
|
+ * 0x0f..00ffffff
|
|
|
|
+ */
|
|
|
|
+ dst_reg->imm = min(src_reg->imm, 63 - imm_log2);
|
|
|
|
+ break;
|
|
|
|
+ case BPF_SUB:
|
|
|
|
+ case BPF_MUL:
|
|
|
|
+ case BPF_RSH:
|
|
|
|
+ case BPF_LSH:
|
|
|
|
+ /* These may be flushed out later */
|
|
|
|
+ default:
|
|
|
|
+ mark_reg_unknown_value(regs, insn->dst_reg);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ mark_reg_unknown_value(regs, insn->dst_reg);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dst_reg->type = UNKNOWN_VALUE;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int evaluate_reg_imm_alu(struct bpf_verifier_env *env,
|
|
static int evaluate_reg_imm_alu(struct bpf_verifier_env *env,
|
|
struct bpf_insn *insn)
|
|
struct bpf_insn *insn)
|
|
{
|
|
{
|
|
@@ -1666,6 +1725,9 @@ static int evaluate_reg_imm_alu(struct bpf_verifier_env *env,
|
|
u8 opcode = BPF_OP(insn->code);
|
|
u8 opcode = BPF_OP(insn->code);
|
|
u64 dst_imm = dst_reg->imm;
|
|
u64 dst_imm = dst_reg->imm;
|
|
|
|
|
|
|
|
+ if (BPF_SRC(insn->code) == BPF_X && src_reg->type == UNKNOWN_VALUE)
|
|
|
|
+ return evaluate_reg_imm_alu_unknown(env, insn);
|
|
|
|
+
|
|
/* dst_reg->type == CONST_IMM here. Simulate execution of insns
|
|
/* dst_reg->type == CONST_IMM here. Simulate execution of insns
|
|
* containing ALU ops. Don't care about overflow or negative
|
|
* containing ALU ops. Don't care about overflow or negative
|
|
* values, just add/sub/... them; registers are in u64.
|
|
* values, just add/sub/... them; registers are in u64.
|