]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bpf: Introduce struct bpf_kfunc_meta
authorIhor Solodrai <ihor.solodrai@linux.dev>
Tue, 20 Jan 2026 22:26:27 +0000 (14:26 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 21 Jan 2026 00:15:56 +0000 (16:15 -0800)
There is code duplication between add_kfunc_call() and
fetch_kfunc_meta() collecting information about a kfunc from BTF.

Introduce struct bpf_kfunc_meta to hold common kfunc BTF data and
implement fetch_kfunc_meta() to fill it in, instead of struct
bpf_kfunc_call_arg_meta directly.

Then use these in add_kfunc_call() and (new) fetch_kfunc_arg_meta()
functions, and fixup previous usages of fetch_kfunc_meta() to
fetch_kfunc_arg_meta().

Besides the code dedup, this change enables add_kfunc_call() to access
kfunc->flags.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
Link: https://lore.kernel.org/r/20260120222638.3976562-3-ihor.solodrai@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c

index c344371feb3304585c705de67b2673668efe53b7..87f0e113b3566ce1f68ba3ed7369b32e399d98b9 100644 (file)
@@ -294,6 +294,14 @@ struct bpf_call_arg_meta {
        s64 const_map_key;
 };
 
+struct bpf_kfunc_meta {
+       struct btf *btf;
+       const struct btf_type *proto;
+       const char *name;
+       const u32 *flags;
+       s32 id;
+};
+
 struct bpf_kfunc_call_arg_meta {
        /* In parameters */
        struct btf *btf;
@@ -3263,16 +3271,68 @@ static struct btf *find_kfunc_desc_btf(struct bpf_verifier_env *env, s16 offset)
        return btf_vmlinux ?: ERR_PTR(-ENOENT);
 }
 
-static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
+static int fetch_kfunc_meta(struct bpf_verifier_env *env,
+                           s32 func_id,
+                           s16 offset,
+                           struct bpf_kfunc_meta *kfunc)
 {
        const struct btf_type *func, *func_proto;
+       const char *func_name;
+       u32 *kfunc_flags;
+       struct btf *btf;
+
+       if (func_id <= 0) {
+               verbose(env, "invalid kernel function btf_id %d\n", func_id);
+               return -EINVAL;
+       }
+
+       btf = find_kfunc_desc_btf(env, offset);
+       if (IS_ERR(btf)) {
+               verbose(env, "failed to find BTF for kernel function\n");
+               return PTR_ERR(btf);
+       }
+
+       /*
+        * Note that kfunc_flags may be NULL at this point, which
+        * means that we couldn't find func_id in any relevant
+        * kfunc_id_set. This most likely indicates an invalid kfunc
+        * call.  However we don't fail with an error here,
+        * and let the caller decide what to do with NULL kfunc->flags.
+        */
+       kfunc_flags = btf_kfunc_flags(btf, func_id, env->prog);
+
+       func = btf_type_by_id(btf, func_id);
+       if (!func || !btf_type_is_func(func)) {
+               verbose(env, "kernel btf_id %d is not a function\n", func_id);
+               return -EINVAL;
+       }
+
+       func_name = btf_name_by_offset(btf, func->name_off);
+       func_proto = btf_type_by_id(btf, func->type);
+       if (!func_proto || !btf_type_is_func_proto(func_proto)) {
+               verbose(env, "kernel function btf_id %d does not have a valid func_proto\n",
+                       func_id);
+               return -EINVAL;
+       }
+
+       memset(kfunc, 0, sizeof(*kfunc));
+       kfunc->btf = btf;
+       kfunc->id = func_id;
+       kfunc->name = func_name;
+       kfunc->proto = func_proto;
+       kfunc->flags = kfunc_flags;
+
+       return 0;
+}
+
+static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
+{
        struct bpf_kfunc_btf_tab *btf_tab;
        struct btf_func_model func_model;
        struct bpf_kfunc_desc_tab *tab;
        struct bpf_prog_aux *prog_aux;
+       struct bpf_kfunc_meta kfunc;
        struct bpf_kfunc_desc *desc;
-       const char *func_name;
-       struct btf *desc_btf;
        unsigned long addr;
        int err;
 
@@ -3322,12 +3382,6 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
                prog_aux->kfunc_btf_tab = btf_tab;
        }
 
-       desc_btf = find_kfunc_desc_btf(env, offset);
-       if (IS_ERR(desc_btf)) {
-               verbose(env, "failed to find BTF for kernel function\n");
-               return PTR_ERR(desc_btf);
-       }
-
        if (find_kfunc_desc(env->prog, func_id, offset))
                return 0;
 
@@ -3336,24 +3390,13 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
                return -E2BIG;
        }
 
-       func = btf_type_by_id(desc_btf, func_id);
-       if (!func || !btf_type_is_func(func)) {
-               verbose(env, "kernel btf_id %u is not a function\n",
-                       func_id);
-               return -EINVAL;
-       }
-       func_proto = btf_type_by_id(desc_btf, func->type);
-       if (!func_proto || !btf_type_is_func_proto(func_proto)) {
-               verbose(env, "kernel function btf_id %u does not have a valid func_proto\n",
-                       func_id);
-               return -EINVAL;
-       }
+       err = fetch_kfunc_meta(env, func_id, offset, &kfunc);
+       if (err)
+               return err;
 
-       func_name = btf_name_by_offset(desc_btf, func->name_off);
-       addr = kallsyms_lookup_name(func_name);
+       addr = kallsyms_lookup_name(kfunc.name);
        if (!addr) {
-               verbose(env, "cannot find address for kernel function %s\n",
-                       func_name);
+               verbose(env, "cannot find address for kernel function %s\n", kfunc.name);
                return -EINVAL;
        }
 
@@ -3363,9 +3406,7 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
                        return err;
        }
 
-       err = btf_distill_func_proto(&env->log, desc_btf,
-                                    func_proto, func_name,
-                                    &func_model);
+       err = btf_distill_func_proto(&env->log, kfunc.btf, kfunc.proto, kfunc.name, &func_model);
        if (err)
                return err;
 
@@ -13696,44 +13737,28 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
        return 0;
 }
 
-static int fetch_kfunc_meta(struct bpf_verifier_env *env,
-                           struct bpf_insn *insn,
-                           struct bpf_kfunc_call_arg_meta *meta,
-                           const char **kfunc_name)
+static int fetch_kfunc_arg_meta(struct bpf_verifier_env *env,
+                               s32 func_id,
+                               s16 offset,
+                               struct bpf_kfunc_call_arg_meta *meta)
 {
-       const struct btf_type *func, *func_proto;
-       u32 func_id, *kfunc_flags;
-       const char *func_name;
-       struct btf *desc_btf;
-
-       if (kfunc_name)
-               *kfunc_name = NULL;
-
-       if (!insn->imm)
-               return -EINVAL;
+       struct bpf_kfunc_meta kfunc;
+       int err;
 
-       desc_btf = find_kfunc_desc_btf(env, insn->off);
-       if (IS_ERR(desc_btf))
-               return PTR_ERR(desc_btf);
+       err = fetch_kfunc_meta(env, func_id, offset, &kfunc);
+       if (err)
+               return err;
 
-       func_id = insn->imm;
-       func = btf_type_by_id(desc_btf, func_id);
-       func_name = btf_name_by_offset(desc_btf, func->name_off);
-       if (kfunc_name)
-               *kfunc_name = func_name;
-       func_proto = btf_type_by_id(desc_btf, func->type);
+       memset(meta, 0, sizeof(*meta));
+       meta->btf = kfunc.btf;
+       meta->func_id = kfunc.id;
+       meta->func_proto = kfunc.proto;
+       meta->func_name = kfunc.name;
 
-       if (!btf_kfunc_is_allowed(desc_btf, func_id, env->prog))
+       if (!kfunc.flags || !btf_kfunc_is_allowed(kfunc.btf, kfunc.id, env->prog))
                return -EACCES;
 
-       kfunc_flags = btf_kfunc_flags(desc_btf, func_id, env->prog);
-
-       memset(meta, 0, sizeof(*meta));
-       meta->btf = desc_btf;
-       meta->func_id = func_id;
-       meta->kfunc_flags = *kfunc_flags;
-       meta->func_proto = func_proto;
-       meta->func_name = func_name;
+       meta->kfunc_flags = *kfunc.flags;
 
        return 0;
 }
@@ -13938,12 +13963,13 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
        if (!insn->imm)
                return 0;
 
-       err = fetch_kfunc_meta(env, insn, &meta, &func_name);
-       if (err == -EACCES && func_name)
-               verbose(env, "calling kernel function %s is not allowed\n", func_name);
+       err = fetch_kfunc_arg_meta(env, insn->imm, insn->off, &meta);
+       if (err == -EACCES && meta.func_name)
+               verbose(env, "calling kernel function %s is not allowed\n", meta.func_name);
        if (err)
                return err;
        desc_btf = meta.btf;
+       func_name = meta.func_name;
        insn_aux = &env->insn_aux_data[insn_idx];
 
        insn_aux->is_iter_next = is_iter_next_kfunc(&meta);
@@ -17789,7 +17815,7 @@ static bool get_call_summary(struct bpf_verifier_env *env, struct bpf_insn *call
        if (bpf_pseudo_kfunc_call(call)) {
                int err;
 
-               err = fetch_kfunc_meta(env, call, &meta, NULL);
+               err = fetch_kfunc_arg_meta(env, call->imm, call->off, &meta);
                if (err < 0)
                        /* error would be reported later */
                        return false;
@@ -18297,7 +18323,7 @@ static int visit_insn(int t, struct bpf_verifier_env *env)
                } else if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
                        struct bpf_kfunc_call_arg_meta meta;
 
-                       ret = fetch_kfunc_meta(env, insn, &meta, NULL);
+                       ret = fetch_kfunc_arg_meta(env, insn->imm, insn->off, &meta);
                        if (ret == 0 && is_iter_next_kfunc(&meta)) {
                                mark_prune_point(env, t);
                                /* Checking and saving state checkpoints at iter_next() call