From nobody Mon Feb 9 08:34:14 2026 Received: from out-178.mta1.migadu.com (out-178.mta1.migadu.com [95.215.58.178]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2988123EA99 for ; Tue, 20 Jan 2026 22:27:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768948042; cv=none; b=hG3oTPo50x/V2IguoNtdGdCPsgbPgkG61mBIs3HAlBvePgDT/HT2x6pOIxQqRXBGB1AGBoIge0HIHD04P2va2CLNnJRjJE1qenGCiGYnXJQvPNWOH7NZlTkKABUX9Dg5Uq8KJ7MRDNSMd9O4ZSFGoDHq6P2HspnpVAqRTgReXrg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768948042; c=relaxed/simple; bh=rjZmLPkDyjV3YQT9jwGX/RjDQpGgyCyKxA3eHqmTeVc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=c+IA1a5CnJFgR0ad5yXrbFdih7wCECTm+ZPK+ZC60R1QggQ5TW2HiYRoC7AX4NLp/JLSch5On4Q7BnWP3Mf7p3SM2x5ZIu36is9HYmZZfJV2UAKKFPED5PAwnBu8aYMJxKa+lmbAmG3xxcAO2AZP/CzzbyZTk0tyRbRJjLAg/IA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=pXRTUdtP; arc=none smtp.client-ip=95.215.58.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="pXRTUdtP" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1768948030; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Fp6NiNyUQI5malyUzVNfrL0QoerafYfWatKSfxALwvE=; b=pXRTUdtPPn+jJ3DkwZH+EjtrprC4u6BGUJBQGuwjFsg/cY/9FOC+5x5BhxK/3uayIbKkGa YfLyMxAhSQS50SEy6vqn07tTfJuhqvKuzfoxIBsFEq++W2gRUEqS3lYHnKWZIFOnVElYoI NzaETASYwlQMzF5KFHyWW3Opnnp4Koc= From: Ihor Solodrai To: Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko , Martin KaFai Lau , Eduard Zingerman Cc: Mykyta Yatsenko , Tejun Heo , Alan Maguire , Benjamin Tissoires , Jiri Kosina , Amery Hung , bpf@vger.kernel.org, linux-kernel@vger.kernel.org, linux-input@vger.kernel.org, sched-ext@lists.linux.dev Subject: [PATCH bpf-next v3 02/13] bpf: Introduce struct bpf_kfunc_meta Date: Tue, 20 Jan 2026 14:26:27 -0800 Message-ID: <20260120222638.3976562-3-ihor.solodrai@linux.dev> In-Reply-To: <20260120222638.3976562-1-ihor.solodrai@linux.dev> References: <20260120222638.3976562-1-ihor.solodrai@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" 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 Signed-off-by: Ihor Solodrai --- kernel/bpf/verifier.c | 156 ++++++++++++++++++++++++------------------ 1 file changed, 91 insertions(+), 65 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c344371feb33..87f0e113b356 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -294,6 +294,14 @@ struct bpf_call_arg_meta { s64 const_map_key; }; =20 +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_v= erifier_env *env, s16 offset) return btf_vmlinux ?: ERR_PTR(-ENOENT); } =20 -static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 o= ffset) +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 <=3D 0) { + verbose(env, "invalid kernel function btf_id %d\n", func_id); + return -EINVAL; + } + + btf =3D 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 =3D btf_kfunc_flags(btf, func_id, env->prog); + + func =3D 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 =3D btf_name_by_offset(btf, func->name_off); + func_proto =3D 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 =3D btf; + kfunc->id =3D func_id; + kfunc->name =3D func_name; + kfunc->proto =3D func_proto; + kfunc->flags =3D kfunc_flags; + + return 0; +} + +static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 o= ffset) +{ 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; =20 @@ -3322,12 +3382,6 @@ static int add_kfunc_call(struct bpf_verifier_env *e= nv, u32 func_id, s16 offset) prog_aux->kfunc_btf_tab =3D btf_tab; } =20 - desc_btf =3D 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; =20 @@ -3336,24 +3390,13 @@ static int add_kfunc_call(struct bpf_verifier_env *= env, u32 func_id, s16 offset) return -E2BIG; } =20 - func =3D 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 =3D 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 =3D fetch_kfunc_meta(env, func_id, offset, &kfunc); + if (err) + return err; =20 - func_name =3D btf_name_by_offset(desc_btf, func->name_off); - addr =3D kallsyms_lookup_name(func_name); + addr =3D 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; } =20 @@ -3363,9 +3406,7 @@ static int add_kfunc_call(struct bpf_verifier_env *en= v, u32 func_id, s16 offset) return err; } =20 - err =3D btf_distill_func_proto(&env->log, desc_btf, - func_proto, func_name, - &func_model); + err =3D btf_distill_func_proto(&env->log, kfunc.btf, kfunc.proto, kfunc.n= ame, &func_model); if (err) return err; =20 @@ -13696,44 +13737,28 @@ static int check_kfunc_args(struct bpf_verifier_e= nv *env, struct bpf_kfunc_call_ return 0; } =20 -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 =3D NULL; - - if (!insn->imm) - return -EINVAL; + struct bpf_kfunc_meta kfunc; + int err; =20 - desc_btf =3D find_kfunc_desc_btf(env, insn->off); - if (IS_ERR(desc_btf)) - return PTR_ERR(desc_btf); + err =3D fetch_kfunc_meta(env, func_id, offset, &kfunc); + if (err) + return err; =20 - func_id =3D insn->imm; - func =3D btf_type_by_id(desc_btf, func_id); - func_name =3D btf_name_by_offset(desc_btf, func->name_off); - if (kfunc_name) - *kfunc_name =3D func_name; - func_proto =3D btf_type_by_id(desc_btf, func->type); + memset(meta, 0, sizeof(*meta)); + meta->btf =3D kfunc.btf; + meta->func_id =3D kfunc.id; + meta->func_proto =3D kfunc.proto; + meta->func_name =3D kfunc.name; =20 - 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; =20 - kfunc_flags =3D btf_kfunc_flags(desc_btf, func_id, env->prog); - - memset(meta, 0, sizeof(*meta)); - meta->btf =3D desc_btf; - meta->func_id =3D func_id; - meta->kfunc_flags =3D *kfunc_flags; - meta->func_proto =3D func_proto; - meta->func_name =3D func_name; + meta->kfunc_flags =3D *kfunc.flags; =20 return 0; } @@ -13938,12 +13963,13 @@ static int check_kfunc_call(struct bpf_verifier_e= nv *env, struct bpf_insn *insn, if (!insn->imm) return 0; =20 - err =3D fetch_kfunc_meta(env, insn, &meta, &func_name); - if (err =3D=3D -EACCES && func_name) - verbose(env, "calling kernel function %s is not allowed\n", func_name); + err =3D fetch_kfunc_arg_meta(env, insn->imm, insn->off, &meta); + if (err =3D=3D -EACCES && meta.func_name) + verbose(env, "calling kernel function %s is not allowed\n", meta.func_na= me); if (err) return err; desc_btf =3D meta.btf; + func_name =3D meta.func_name; insn_aux =3D &env->insn_aux_data[insn_idx]; =20 insn_aux->is_iter_next =3D is_iter_next_kfunc(&meta); @@ -17789,7 +17815,7 @@ static bool get_call_summary(struct bpf_verifier_en= v *env, struct bpf_insn *call if (bpf_pseudo_kfunc_call(call)) { int err; =20 - err =3D fetch_kfunc_meta(env, call, &meta, NULL); + err =3D 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_en= v *env) } else if (insn->src_reg =3D=3D BPF_PSEUDO_KFUNC_CALL) { struct bpf_kfunc_call_arg_meta meta; =20 - ret =3D fetch_kfunc_meta(env, insn, &meta, NULL); + ret =3D fetch_kfunc_arg_meta(env, insn->imm, insn->off, &meta); if (ret =3D=3D 0 && is_iter_next_kfunc(&meta)) { mark_prune_point(env, t); /* Checking and saving state checkpoints at iter_next() call --=20 2.52.0