add_subprog_and_kfunc relocates kfunc CALLs by patching insn->imm and src_reg, and bpf_prog_calc_tag has no rule to mask kfunc CALL fields. The tag has to be computed over the unmodified user-supplied insns to match the excl_prog_hash userspace signed, so move the call to bpf_prog_load right after signature verification. Signed-off-by: KP Singh --- kernel/bpf/syscall.c | 7 +++++++ kernel/bpf/verifier.c | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 6d1db5eaad3c..39ebd825c136 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -3086,6 +3086,13 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) } prog->aux->is_kernel = uattr.is_kernel; + /* Hash insns now, before any verifier-side rewrite, so prog->digest + * matches the excl_prog_hash userspace computed. + */ + err = bpf_prog_calc_tag(prog); + if (err) + goto free_prog; + prog->orig_prog = NULL; prog->jited = 0; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 7fb88e1cd7c4..f0e45cfa5b34 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -18434,10 +18434,6 @@ static int check_and_resolve_insns(struct bpf_verifier_env *env) int insn_cnt = env->prog->len; int i, err; - err = bpf_prog_calc_tag(env->prog); - if (err) - return err; - for (i = 0; i < insn_cnt; i++, insn++) { if (insn->dst_reg >= MAX_BPF_REG) { verbose(env, "R%d is invalid\n", insn->dst_reg); -- 2.53.0