The compiler sometimes stores the result of a PTR_TO_ARENA + SCALAR addition into the scalar register rather than the pointer register. Handle this case by upgrading the destination scalar register to PTR_TO_ARENA, matching the existing handling when the destination is already PTR_TO_ARENA. Signed-off-by: Emil Tsalapatis Acked-by: Song Liu --- kernel/bpf/verifier.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 8c1cf2eb6cbb..30bb71f90477 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -16297,11 +16297,34 @@ static int adjust_reg_min_max_vals(struct bpf_verifier_env *env, int err; dst_reg = ®s[insn->dst_reg]; - src_reg = NULL; + if (BPF_SRC(insn->code) == BPF_X) + src_reg = ®s[insn->src_reg]; + else + src_reg = NULL; - if (dst_reg->type == PTR_TO_ARENA) { + /* Case where at least one operand is an arena. */ + if (dst_reg->type == PTR_TO_ARENA || (src_reg && src_reg->type == PTR_TO_ARENA)) { struct bpf_insn_aux_data *aux = cur_aux(env); + /* The compiler sometimes stores the result of a SCALAR/PTR_TO_ARENA + * operation into the scalar register. Properly mark the result as + * holding an arena pointer. + */ + if (dst_reg->type != PTR_TO_ARENA) { + /* Can't do arena arithmetic with non-scalars. */ + if (dst_reg->type != SCALAR_VALUE) { + verbose(env, "R%d pointer %s arena prohibited\n", + insn->dst_reg, + bpf_alu_string[opcode >> 4]); + return -EACCES; + } + + /* We have a SCALAR_PTR_TO_ARENA operation, + * propagate the info to dst_reg. */ + *dst_reg = *src_reg; + } + + if (BPF_CLASS(insn->code) == BPF_ALU64) /* * 32-bit operations zero upper bits automatically. -- 2.53.0