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 v2 16/18] bpf: Tag nullable kfunc pointer args with PTR_MAYBE_NULL
Date: Fri, 24 Jul 2026 12:08:10 -0700 [thread overview]
Message-ID: <20260724190813.1458271-17-ameryhung@gmail.com> (raw)
In-Reply-To: <20260724190813.1458271-1-ameryhung@gmail.com>
Now that get_kfunc_ptr_arg_type() classifies a kfunc pointer argument
from its BTF alone, express a nullable argument by OR-ing PTR_MAYBE_NULL
into the classified type, and resolve a NULL register after
classification instead of before it.
Previously check_kfunc_args() short-circuited a nullable argument passed
a NULL register with a continue placed before get_kfunc_ptr_arg_type(),
so the NULL never reached classification. That kept a register-state
decision (bpf_register_is_null()) ahead of the BTF-based classification.
This mirrors how helper arguments carry PTR_MAYBE_NULL in their
bpf_arg_type and is a step toward describing kfuncs with a bpf_func_proto:
the nullability now travels with the per-argument classification, so it is
captured when the prototype is generated at add-call time.
Signed-off-by: Amery Hung <ameryhung@gmail.com>
---
kernel/bpf/verifier.c | 156 ++++++++++++++++++++----------------------
1 file changed, 74 insertions(+), 82 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 76a84574b23e..3b357007e893 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -11361,93 +11361,85 @@ get_kfunc_ptr_arg_type(struct bpf_verifier_env *env, struct bpf_call_arg_meta *m
int arg, int nargs, argno_t argno)
{
bool arg_mem_size = false;
-
- if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] ||
- meta->func_id == special_kfunc_list[KF_bpf_session_is_return] ||
- meta->func_id == special_kfunc_list[KF_bpf_session_cookie])
- return KF_ARG_PTR_TO_CTX;
+ int arg_type;
/* In this function, we verify the kfunc's BTF as per the argument type,
* leaving the rest of the verification with respect to the register
* type to our caller. When a set of conditions hold in the BTF type of
* arguments, we resolve it to a known kfunc_ptr_arg_type.
*/
- if (btf_is_prog_ctx_type(&env->log, meta->btf, t, resolve_prog_type(env->prog), arg))
- return KF_ARG_PTR_TO_CTX;
-
- if (is_kfunc_arg_alloc_obj(meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_ALLOC_BTF_ID;
-
- if (is_kfunc_arg_refcounted_kptr(meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_REFCOUNTED_KPTR;
-
- if (is_kfunc_arg_dynptr(meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_DYNPTR;
-
- if (is_kfunc_arg_iter(meta, arg, &args[arg]))
- return KF_ARG_PTR_TO_ITER;
-
- if (is_kfunc_arg_list_head(meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_LIST_HEAD;
-
- if (is_kfunc_arg_list_node(meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_LIST_NODE;
-
- if (is_kfunc_arg_rbtree_root(meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_RB_ROOT;
-
- if (is_kfunc_arg_rbtree_node(meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_RB_NODE;
-
- if (is_kfunc_arg_const_str(meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_CONST_STR;
-
- if (is_kfunc_arg_const_map(meta->btf, &args[arg]))
- return KF_ARG_CONST_MAP_PTR;
-
- if (is_kfunc_arg_map(meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_BTF_ID;
-
- if (is_kfunc_arg_wq(meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_WORKQUEUE;
-
- if (is_kfunc_arg_timer(meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_TIMER;
-
- if (is_kfunc_arg_task_work(meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_TASK_WORK;
-
- if (is_kfunc_arg_irq_flag(meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_IRQ_FLAG;
-
- if (is_kfunc_arg_res_spin_lock(meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_RES_SPIN_LOCK;
-
- if (is_kfunc_arg_callback(env, meta->btf, &args[arg]))
- return KF_ARG_PTR_TO_CALLBACK;
-
- if (arg + 1 < nargs &&
- (is_kfunc_arg_mem_size(meta->btf, &args[arg + 1]) ||
- is_kfunc_arg_const_mem_size(meta->btf, &args[arg + 1])))
- arg_mem_size = true;
+ if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] ||
+ meta->func_id == special_kfunc_list[KF_bpf_session_is_return] ||
+ meta->func_id == special_kfunc_list[KF_bpf_session_cookie])
+ arg_type = KF_ARG_PTR_TO_CTX;
+ else if (btf_is_prog_ctx_type(&env->log, meta->btf, t, resolve_prog_type(env->prog), arg))
+ arg_type = KF_ARG_PTR_TO_CTX;
+ else if (is_kfunc_arg_alloc_obj(meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_ALLOC_BTF_ID;
+ else if (is_kfunc_arg_refcounted_kptr(meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_REFCOUNTED_KPTR;
+ else if (is_kfunc_arg_dynptr(meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_DYNPTR;
+ else if (is_kfunc_arg_iter(meta, arg, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_ITER;
+ else if (is_kfunc_arg_list_head(meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_LIST_HEAD;
+ else if (is_kfunc_arg_list_node(meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_LIST_NODE;
+ else if (is_kfunc_arg_rbtree_root(meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_RB_ROOT;
+ else if (is_kfunc_arg_rbtree_node(meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_RB_NODE;
+ else if (is_kfunc_arg_const_str(meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_CONST_STR;
+ else if (is_kfunc_arg_const_map(meta->btf, &args[arg]))
+ arg_type = KF_ARG_CONST_MAP_PTR;
+ else if (is_kfunc_arg_map(meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_BTF_ID;
+ else if (is_kfunc_arg_wq(meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_WORKQUEUE;
+ else if (is_kfunc_arg_timer(meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_TIMER;
+ else if (is_kfunc_arg_task_work(meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_TASK_WORK;
+ else if (is_kfunc_arg_irq_flag(meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_IRQ_FLAG;
+ else if (is_kfunc_arg_res_spin_lock(meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_RES_SPIN_LOCK;
+ else if (is_kfunc_arg_callback(env, meta->btf, &args[arg]))
+ arg_type = KF_ARG_PTR_TO_CALLBACK;
+ else {
+ if (arg + 1 < nargs &&
+ (is_kfunc_arg_mem_size(meta->btf, &args[arg + 1]) ||
+ is_kfunc_arg_const_mem_size(meta->btf, &args[arg + 1])))
+ arg_mem_size = true;
+
+ if (btf_type_is_struct(ref_t) && !arg_mem_size) {
+ /* A pointer to a struct without a size argument is classified
+ * as KF_ARG_PTR_TO_BTF_ID.
+ */
+ arg_type = KF_ARG_PTR_TO_BTF_ID;
+ } else if (!btf_type_is_scalar(ref_t) &&
+ !__btf_type_is_scalar_struct(env, meta->btf, ref_t, 0) &&
+ (arg_mem_size ? !btf_type_is_void(ref_t) : 1)) {
+ verbose(env, "%s pointer type %s %s must point to %sscalar, or struct with scalar\n",
+ reg_arg_name(env, argno),
+ btf_type_str(ref_t), ref_tname, arg_mem_size ? "void, " : "");
+ return -EINVAL;
+ } else {
+ /* Otherwise this is a memory buffer supported by
+ * check_helper_mem_access(): a pointer to a scalar, or to void
+ * when paired with a size argument. The access size is derived
+ * from the pointed-to BTF type unless a size argument follows.
+ */
+ arg_type = arg_mem_size ? KF_ARG_PTR_TO_MEM : KF_ARG_PTR_TO_MEM | MEM_FIXED_SIZE;
+ }
+ }
- /* A pointer to a struct without a size argument is classified as KF_ARG_PTR_TO_BTF_ID */
- if (btf_type_is_struct(ref_t) && !arg_mem_size)
- return KF_ARG_PTR_TO_BTF_ID;
+ if (is_kfunc_arg_nullable(meta->btf, &args[arg]))
+ arg_type |= PTR_MAYBE_NULL;
- /*
- * Otherwise this is a memory buffer supported by check_helper_mem_access(): a pointer
- * to a scalar, or to void when paired with a size argument. The access size is derived
- * from the pointed-to BTF type unless a size argument follows.
- */
- if (!btf_type_is_scalar(ref_t) && !__btf_type_is_scalar_struct(env, meta->btf, ref_t, 0) &&
- (arg_mem_size ? !btf_type_is_void(ref_t) : 1)) {
- verbose(env, "%s pointer type %s %s must point to %sscalar, or struct with scalar\n",
- reg_arg_name(env, argno),
- btf_type_str(ref_t), ref_tname, arg_mem_size ? "void, " : "");
- return -EINVAL;
- }
- return arg_mem_size ? KF_ARG_PTR_TO_MEM : KF_ARG_PTR_TO_MEM | MEM_FIXED_SIZE;
+ return arg_type;
}
static int process_kf_arg_ptr_to_btf_id(struct bpf_verifier_env *env,
@@ -12135,14 +12127,14 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
ref_tname = btf_name_by_offset(btf, ref_t->name_off);
- if (is_kfunc_arg_nullable(meta->btf, &args[i]) && bpf_register_is_null(reg))
- continue;
-
kf_arg_type = get_kfunc_ptr_arg_type(env, meta, t, ref_t, ref_tname,
args, i, nargs, argno);
if (kf_arg_type < 0)
return kf_arg_type;
+ if (bpf_register_is_null(reg) && type_may_be_null(kf_arg_type))
+ continue;
+
if (is_kfunc_arg_map(btf, &args[i])) {
ref_id = *reg2btf_ids[CONST_PTR_TO_MAP];
ref_t = btf_type_by_id(btf_vmlinux, ref_id);
--
2.52.0
next prev parent reply other threads:[~2026-07-24 19:08 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-24 19:07 [PATCH bpf-next v2 00/18] Generate bpf_func_proto for kfunc Amery Hung
2026-07-24 19:07 ` [PATCH bpf-next v2 01/18] bpf: Drop process_timer_func wrappers Amery Hung
2026-07-24 19:07 ` [PATCH bpf-next v2 02/18] bpf: Unify const map ptr argument checking for helpers and kfuncs Amery Hung
2026-07-24 19:28 ` sashiko-bot
2026-07-24 20:49 ` Amery Hung
2026-07-24 21:29 ` Kumar Kartikeya Dwivedi
2026-07-24 19:07 ` [PATCH bpf-next v2 03/18] bpf: Split kfunc map argument into __const_map and __map Amery Hung
2026-07-24 19:07 ` [PATCH bpf-next v2 04/18] bpf: Pass kfunc meta to mem and mem_size check Amery Hung
2026-07-24 19:07 ` [PATCH bpf-next v2 05/18] bpf: Check helper and kfunc mem+size arguments identically Amery Hung
2026-07-24 19:08 ` [PATCH bpf-next v2 06/18] selftests/bpf: Add tests for helper and kfunc mem+size arguments Amery Hung
2026-07-24 19:25 ` sashiko-bot
2026-07-24 19:08 ` [PATCH bpf-next v2 07/18] bpf: Check fixed-size mem args of helpers and kfuncs the same way Amery Hung
2026-07-24 19:32 ` sashiko-bot
2026-07-24 20:39 ` Amery Hung
2026-07-24 19:08 ` [PATCH bpf-next v2 08/18] bpf: Express ARG_CONST_SIZE_OR_ZERO as ARG_CONST_SIZE | SCALAR_MAYBE_ZERO Amery Hung
2026-07-24 19:08 ` [PATCH bpf-next v2 09/18] bpf: Rename ARG_CONST_SIZE{,_OR_ZERO} to ARG_MEM_SIZE{,_OR_ZERO} Amery Hung
2026-07-24 19:08 ` [PATCH bpf-next v2 10/18] bpf: Fold __szk const size handling into the scalar arg path Amery Hung
2026-07-24 19:08 ` [PATCH bpf-next v2 11/18] bpf: Classify kfunc mem_size args from BTF without register state Amery Hung
2026-07-24 19:38 ` sashiko-bot
2026-07-24 22:52 ` Amery Hung
2026-07-24 19:08 ` [PATCH bpf-next v2 12/18] bpf: Handle NULL kfunc pointer args without a KF_ARG_PTR_TO_NULL type Amery Hung
2026-07-24 19:08 ` [PATCH bpf-next v2 13/18] bpf: Distinguish fixed- and variable-size kfunc mem args with MEM_FIXED_SIZE Amery Hung
2026-07-24 19:08 ` [PATCH bpf-next v2 14/18] bpf: Check helper mem+size in ARG_PTR_TO_MEM case Amery Hung
2026-07-24 19:47 ` sashiko-bot
2026-07-24 21:10 ` Amery Hung
2026-07-24 19:08 ` [PATCH bpf-next v2 15/18] bpf: Classify kfunc pointer arguments from BTF, resolve type against the register Amery Hung
2026-07-24 19:08 ` Amery Hung [this message]
2026-07-24 19:38 ` [PATCH bpf-next v2 16/18] bpf: Tag nullable kfunc pointer args with PTR_MAYBE_NULL sashiko-bot
2026-07-24 19:08 ` [PATCH bpf-next v2 17/18] bpf: Classify scalar kfunc arguments from BTF Amery Hung
2026-07-24 19:08 ` [PATCH bpf-next v2 18/18] bpf: Generate kfunc argument prototype at add-call time Amery Hung
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=20260724190813.1458271-17-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