]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bpf: Search and add kfuncs in struct_ops prologue and epilogue
authorAmery Hung <amery.hung@bytedance.com>
Tue, 25 Feb 2025 23:35:44 +0000 (15:35 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 26 Feb 2025 03:04:43 +0000 (19:04 -0800)
Currently, add_kfunc_call() is only invoked once before the main
verification loop. Therefore, the verifier could not find the
bpf_kfunc_btf_tab of a new kfunc call which is not seen in user defined
struct_ops operators but introduced in gen_prologue or gen_epilogue
during do_misc_fixup(). Fix this by searching kfuncs in the patching
instruction buffer and add them to prog->aux->kfunc_tab.

Signed-off-by: Amery Hung <amery.hung@bytedance.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Acked-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://lore.kernel.org/r/20250225233545.285481-1-ameryhung@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c

index 942c0d2df258a88dd6ec0f9de402655897f567b3..dcd0da4e62fca155fbd3d81c1ce5ca5c50c041fb 100644 (file)
@@ -3275,6 +3275,21 @@ bpf_jit_find_kfunc_model(const struct bpf_prog *prog,
        return res ? &res->func_model : NULL;
 }
 
+static int add_kfunc_in_insns(struct bpf_verifier_env *env,
+                             struct bpf_insn *insn, int cnt)
+{
+       int i, ret;
+
+       for (i = 0; i < cnt; i++, insn++) {
+               if (bpf_pseudo_kfunc_call(insn)) {
+                       ret = add_kfunc_call(env, insn->imm, insn->off);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+       return 0;
+}
+
 static int add_subprog_and_kfunc(struct bpf_verifier_env *env)
 {
        struct bpf_subprog_info *subprog = env->subprog_info;
@@ -20433,7 +20448,7 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
 {
        struct bpf_subprog_info *subprogs = env->subprog_info;
        const struct bpf_verifier_ops *ops = env->ops;
-       int i, cnt, size, ctx_field_size, delta = 0, epilogue_cnt = 0;
+       int i, cnt, size, ctx_field_size, ret, delta = 0, epilogue_cnt = 0;
        const int insn_cnt = env->prog->len;
        struct bpf_insn *epilogue_buf = env->epilogue_buf;
        struct bpf_insn *insn_buf = env->insn_buf;
@@ -20462,6 +20477,10 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
                                return -ENOMEM;
                        env->prog = new_prog;
                        delta += cnt - 1;
+
+                       ret = add_kfunc_in_insns(env, epilogue_buf, epilogue_cnt - 1);
+                       if (ret < 0)
+                               return ret;
                }
        }
 
@@ -20482,6 +20501,10 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
 
                        env->prog = new_prog;
                        delta += cnt - 1;
+
+                       ret = add_kfunc_in_insns(env, insn_buf, cnt - 1);
+                       if (ret < 0)
+                               return ret;
                }
        }