bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Amery Hung <ameryhung@gmail.com>
To: bpf@vger.kernel.org
Cc: alexei.starovoitov@gmail.com, andrii@kernel.org,
	daniel@iogearbox.net, eddyz87@gmail.com, memxor@gmail.com,
	ameryhung@gmail.com, kernel-team@meta.com
Subject: [PATCH bpf-next v3 02/11] bpf: Identify subprog calls in argument metadata
Date: Mon, 28 Sep 2026 11:53:25 -0700	[thread overview]
Message-ID: <20260928185334.1004200-3-ameryhung@gmail.com> (raw)
In-Reply-To: <20260928185334.1004200-1-ameryhung@gmail.com>

Prepare subprog calls to use the common check_func_args() path. That
checker distinguishes call kinds through bpf_call_arg_meta, but
btf_check_func_arg_match() leaves both BTF and the function ID zero even
though it validates a program-BTF signature.

Represent a subprog call with a non-NULL BTF and a zero function ID.
Define helpers as NULL BTF plus nonzero ID, and kfuncs as non-NULL BTF
plus nonzero ID. Requiring a nonzero kfunc ID also prevents unavailable
special-kfunc IDs from matching subprog metadata. The corresponding
subprog predicate is introduced later alongside its first use.

Setting BTF would expose checks that treat every BTF-backed call as a
kfunc. Restrict kfunc-only BTF parameter lookup, register admission,
release diagnostics, no-cast alias, and projection handling to actual
kfuncs.

The BTF is not modified here, but bpf_call_arg_meta::btf and several
downstream consumers use non-const pointers. Match those existing types
instead of broadening this series with a const-correctness cleanup.

No functional change is intended.

Signed-off-by: Amery Hung <ameryhung@gmail.com>
---
 kernel/bpf/verifier.c | 36 +++++++++++++++++++++++-------------
 1 file changed, 23 insertions(+), 13 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index b54873c8b95e..de9276a3ee4d 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -8639,18 +8639,27 @@ static bool arg_type_is_scalar(enum bpf_arg_type type)
 }
 
 /*
- * A kfunc is named by a BTF ID, which can take the same numeric value as an
- * enum bpf_func_id. Only test meta->func_id against a BPF_FUNC_* once the call
- * is known to be to a helper; meta->btf is set only for a kfunc.
+ * A helper has no BTF and a nonzero function ID. A kfunc has both, while a
+ * BPF subprogram has BTF and a zero function ID.
  */
+static bool is_helper(const struct bpf_call_arg_meta *meta)
+{
+	return !meta->btf && meta->func_id;
+}
+
 static bool is_helper_call(const struct bpf_call_arg_meta *meta, enum bpf_func_id func_id)
 {
-	return !meta->btf && meta->func_id == func_id;
+	return is_helper(meta) && meta->func_id == func_id;
+}
+
+static bool is_kfunc(const struct bpf_call_arg_meta *meta)
+{
+	return meta->btf && meta->func_id;
 }
 
 static bool is_kfunc_call(const struct bpf_call_arg_meta *meta, u32 btf_id)
 {
-	return meta->btf && meta->func_id == btf_id;
+	return is_kfunc(meta) && meta->func_id == btf_id;
 }
 
 static int resolve_map_arg_type(struct bpf_verifier_env *env,
@@ -8963,7 +8972,7 @@ static int check_func_arg_release(struct bpf_verifier_env *env, struct bpf_reg_s
 	verbose(env, "release function %s expects referenced PTR_TO_BTF_ID passed to %s\n",
 		meta->func_name, reg_arg_name(env, argno));
 
-	if (meta->btf) {
+	if (is_kfunc(meta)) {
 		const struct btf_param *btf_arg;
 		const struct btf_type *t;
 		u32 ref_id;
@@ -9017,7 +9026,7 @@ static int check_reg_type(struct bpf_verifier_env *env, struct bpf_reg_state *re
 		verifier_bug(env, "unsupported arg type %d", arg_type);
 		return -EFAULT;
 	}
-	if (meta->btf && base_type(arg_type) == ARG_PTR_TO_BTF_ID &&
+	if (is_kfunc(meta) && base_type(arg_type) == ARG_PTR_TO_BTF_ID &&
 	    (base_type(type) == PTR_TO_BTF_ID || reg2btf_ids[base_type(type)]))
 		goto found;
 
@@ -9040,7 +9049,7 @@ static int check_reg_type(struct bpf_verifier_env *env, struct bpf_reg_state *re
 	if (base_type(arg_type) == ARG_PTR_TO_MEM)
 		type &= ~DYNPTR_TYPE_FLAG_MASK;
 	/* Allow allocated memory for kfunc ARG_PTR_TO_MEM but not helper. */
-	if (meta->btf && base_type(arg_type) == ARG_PTR_TO_MEM &&
+	if (is_kfunc(meta) && base_type(arg_type) == ARG_PTR_TO_MEM &&
 	    type_is_ptr_alloc_obj(type))
 		type = PTR_TO_MEM;
 
@@ -9363,7 +9372,8 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 p
 			  struct bpf_call_arg_meta *meta,
 			  int insn_idx)
 {
-	const struct btf_param *btf_arg = meta->btf ? &btf_params(meta->func_proto)[arg] : NULL;
+	const struct btf_param *btf_arg = is_kfunc(meta) ?
+					  &btf_params(meta->func_proto)[arg] : NULL;
 	const struct bpf_func_proto *fn = meta->fn;
 	struct bpf_func_state *caller = cur_func(env);
 	struct bpf_reg_state *regs = cur_regs(env);
@@ -10789,7 +10799,7 @@ static int setup_func_entry(struct bpf_verifier_env *env, int subprog, int calls
 }
 
 static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
-				    const struct btf *btf,
+				    struct btf *btf,
 				    struct bpf_reg_state *regs)
 {
 	struct bpf_subprog_info *sub = subprog_info(env, subprog);
@@ -10801,8 +10811,8 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
 	u32 i;
 	int ret, err;
 
-	/* Leave btf and func_id zero: this is neither a helper nor a kfunc. */
 	memset(&meta, 0, sizeof(meta));
+	meta.btf = btf;
 	meta.func_name = bpf_subprog_name(env, subprog);
 
 	ret = btf_prepare_func_args(env, subprog);
@@ -13783,7 +13793,7 @@ static int process_arg_ptr_to_btf_id(struct bpf_verifier_env *env, struct bpf_re
 	 * resolve types.
 	 */
 	if ((arg_type_is_release(arg_type) && !is_helper_call(meta, BPF_FUNC_sk_release)) ||
-	    (meta->btf && btf_type_ids_nocast_alias(&env->log, reg_btf, reg_btf_id,
+	    (is_kfunc(meta) && btf_type_ids_nocast_alias(&env->log, reg_btf, reg_btf_id,
 						    arg_btf, arg_btf_id)))
 		strict_type_match = true;
 
@@ -13800,7 +13810,7 @@ static int process_arg_ptr_to_btf_id(struct bpf_verifier_env *env, struct bpf_re
 	 * actually use it -- it must cast to the underlying type. So we allow
 	 * caller to pass in the underlying type.
 	 */
-	taking_projection = meta->btf && btf_is_projection_of(arg_tname, reg_tname);
+	taking_projection = is_kfunc(meta) && btf_is_projection_of(arg_tname, reg_tname);
 	if (!taking_projection && !struct_same) {
 		verbose(env, "%s %s expected pointer to %s %s but %s has a pointer to %s %s\n",
 			meta->func_name, reg_arg_name(env, argno),
-- 
2.52.0


  parent reply	other threads:[~2026-09-28 18:53 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-28 18:53 [PATCH bpf-next v3 00/11] Unify subprog argument checks Amery Hung
2026-09-28 18:53 ` [PATCH bpf-next v3 01/11] bpf: Fix kfunc BTF parameter lookups after wide arguments Amery Hung
2026-09-28 18:53 ` Amery Hung [this message]
2026-09-28 18:53 ` [PATCH bpf-next v3 03/11] bpf: Build argument prototypes for subprog calls Amery Hung
2026-09-28 18:53 ` [PATCH bpf-next v3 04/11] bpf: Check subprog scalar arguments in the common path Amery Hung
2026-09-28 18:53 ` [PATCH bpf-next v3 05/11] bpf: Check global subprog untrusted " Amery Hung
2026-09-28 18:53 ` [PATCH bpf-next v3 06/11] bpf: Check subprog context " Amery Hung
2026-09-28 18:53 ` [PATCH bpf-next v3 07/11] bpf: Check subprog arena " Amery Hung
2026-09-28 18:53 ` [PATCH bpf-next v3 08/11] bpf: Check subprog dynptr " Amery Hung
2026-09-28 18:53 ` [PATCH bpf-next v3 09/11] bpf: Check global subprog BTF-ID " Amery Hung
2026-09-28 18:53 ` [PATCH bpf-next v3 10/11] bpf: Check global subprog memory " Amery Hung
2026-09-28 19:53   ` bot+bpf-ci
2026-09-28 18:53 ` [PATCH bpf-next v3 11/11] bpf: Check all subprog " Amery Hung
2026-09-29 10:40 ` [PATCH bpf-next v3 00/11] Unify subprog argument checks patchwork-bot+netdevbpf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260928185334.1004200-3-ameryhung@gmail.com \
    --to=ameryhung@gmail.com \
    --cc=alexei.starovoitov@gmail.com \
    --cc=andrii@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=kernel-team@meta.com \
    --cc=memxor@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).