bpf: Introduce struct bpf_kfunc_meta

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>
This commit is contained in:
Ihor Solodrai 2026-01-20 14:26:27 -08:00 committed by Alexei Starovoitov
parent ea073d1818
commit 08ca87d632

View 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;
struct bpf_kfunc_meta kfunc;
int err;
if (kfunc_name)
*kfunc_name = NULL;
if (!insn->imm)
return -EINVAL;
desc_btf = find_kfunc_desc_btf(env, insn->off);
if (IS_ERR(desc_btf))
return PTR_ERR(desc_btf);
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);
if (!btf_kfunc_is_allowed(desc_btf, func_id, env->prog))
return -EACCES;
kfunc_flags = btf_kfunc_flags(desc_btf, func_id, env->prog);
err = fetch_kfunc_meta(env, func_id, offset, &kfunc);
if (err)
return err;
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->btf = kfunc.btf;
meta->func_id = kfunc.id;
meta->func_proto = kfunc.proto;
meta->func_name = kfunc.name;
if (!kfunc.flags || !btf_kfunc_is_allowed(kfunc.btf, kfunc.id, env->prog))
return -EACCES;
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