In the verifier, we currently reset all of the registers containing caller saved args before updating the callee's return register (REG0). In a follow-on patch, we will need to be able to be able to inspect the caller saved registers when updating REG0 to determine if a dynptr that's passed to a helper function was allocated by a helper, or allocated by a program. This patch therefore updates check_helper_call() to clear the caller saved regs after updating REG0. Signed-off-by: David Vernet <void@xxxxxxxxxxxxx> --- kernel/bpf/verifier.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 096fdac70165..938ba1536249 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -7348,11 +7348,9 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn if (err) return err; - /* reset caller saved regs */ - for (i = 0; i < CALLER_SAVED_REGS; i++) { - mark_reg_not_init(env, regs, caller_saved[i]); - check_reg_arg(env, caller_saved[i], DST_OP_NO_MARK); - } + /* reset return reg */ + mark_reg_not_init(env, regs, BPF_REG_0); + check_reg_arg(env, BPF_REG_0, DST_OP_NO_MARK); /* helper call returns 64-bit value. */ regs[BPF_REG_0].subreg_def = DEF_NOT_SUBREG; @@ -7488,6 +7486,13 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn regs[BPF_REG_0].ref_obj_id = dynptr_id; } + /* reset remaining caller saved regs */ + BUILD_BUG_ON(caller_saved[0] != BPF_REG_0); + for (i = 1; i < CALLER_SAVED_REGS; i++) { + mark_reg_not_init(env, regs, caller_saved[i]); + check_reg_arg(env, caller_saved[i], DST_OP_NO_MARK); + } + do_refine_retval_range(regs, fn->ret_type, func_id, &meta); err = check_map_func_compatibility(env, meta.map_ptr, func_id); -- 2.30.2