From: bot+bpf-ci@kernel.org
To: ameryhung@gmail.com,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,ast@kernel.org,andrii@kernel.org,daniel@iogearbox.net,martin.lau@kernel.org,eddyz87@gmail.com,yonghong.song@linux.dev,mason@kernel.org,ihor.solodrai@linux.dev
Subject: Re: [PATCH bpf-next v1 18/22] bpf: Admit kfunc argument registers through check_reg_type()
Date: Sat, 5 Sep 2026 23:23:31 +0000 (UTC) [thread overview]
Message-ID: <58079fda8b9a98ec66a54e8c1cb80e4eaedf82cc5fda7f8cebef10fb1b4e266d@mail.kernel.org> (raw)
In-Reply-To: <20260905220117.922028-19-ameryhung@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 13838 bytes --]
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index bd3fea62aa02..cad49ea5fdfa 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
[ ... ]
> @@ -8251,7 +8239,7 @@ static const struct bpf_reg_types mem_types = {
> },
> };
>
> -static const struct bpf_reg_types spin_lock_types = {
> +static const struct bpf_reg_types map_value_or_alloc_obj_types = {
> .types = {
> PTR_TO_MAP_VALUE,
> PTR_TO_BTF_ID | MEM_ALLOC,
[ ... ]
> @@ -8280,7 +8268,29 @@ static const struct bpf_reg_types percpu_btf_ptr_types = {
> static const struct bpf_reg_types func_ptr_types = { .types = { PTR_TO_FUNC } };
> static const struct bpf_reg_types stack_ptr_types = { .types = { PTR_TO_STACK } };
> static const struct bpf_reg_types const_str_ptr_types = { .types = { PTR_TO_MAP_VALUE } };
> -static const struct bpf_reg_types timer_types = { .types = { PTR_TO_MAP_VALUE } };
> +static const struct bpf_reg_types map_value_types = { .types = { PTR_TO_MAP_VALUE } };
> +static const struct bpf_reg_types arena_types = {
> + .types = {
> + PTR_TO_ARENA,
> + SCALAR_VALUE,
> + }
> +};
> +
> +static const struct bpf_reg_types alloc_obj_types = {
> + .types = {
> + PTR_TO_BTF_ID | MEM_ALLOC,
> + PTR_TO_BTF_ID | MEM_ALLOC | MEM_PERCPU,
> + }
> +};
> +
> +static const struct bpf_reg_types alloc_obj_or_non_own_ref_types = {
> + .types = {
> + PTR_TO_BTF_ID | MEM_ALLOC,
> + PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF,
> + PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU,
> + }
> +};
Does alloc_obj_or_non_own_ref_types need a diagnostic improvement?
reg_type_str() has no textual prefix for MEM_ALLOC or NON_OWN_REF and
renders PTR_TO_BTF_ID as the bare stem "ptr_". The first two entries both
render as "ptr_" and the third as "rcu_ptr_", giving users the
non-actionable list "ptr_, ptr_, rcu_ptr_". The selftest updates confirm
this is what users see:
rbtree_fail.c: __msg("R2 type=scalar expected=ptr_, ptr_, rcu_ptr_")
refcounted_kptr_fail.c: __msg("R1 type=ctx expected=ptr_, ptr_, rcu_ptr_")
These replace specific messages like "R1 is neither owning or non-owning
ref". The changelog claims "The reason continues to report the actual
register type and all accepted register types", which is literally true but
not useful here: three distinct ownership states collapse to two
indistinguishable strings, and "ptr_" is a dangling stem. Either
reg_type_str() needs prefixes for MEM_ALLOC/NON_OWN_REF, or
ARG_PTR_TO_REFCOUNTED_KPTR / ARG_PTR_TO_LIST_NODE / ARG_PTR_TO_RB_NODE
should keep an ownership-specific message.
> @@ -8310,16 +8320,32 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = {
> #endif
> [ARG_PTR_TO_SOCKET] = &fullsock_types,
> [ARG_PTR_TO_BTF_ID] = &btf_ptr_types,
> - [ARG_PTR_TO_SPIN_LOCK] = &spin_lock_types,
> + [ARG_PTR_TO_SPIN_LOCK] = &map_value_or_alloc_obj_types,
> [ARG_PTR_TO_MEM] = &mem_types,
> [ARG_PTR_TO_RINGBUF_MEM] = &ringbuf_mem_types,
> [ARG_PTR_TO_PERCPU_BTF_ID] = &percpu_btf_ptr_types,
> [ARG_PTR_TO_FUNC] = &func_ptr_types,
> [ARG_PTR_TO_STACK] = &stack_ptr_types,
> [ARG_PTR_TO_CONST_STR] = &const_str_ptr_types,
> - [ARG_PTR_TO_TIMER] = &timer_types,
> + [ARG_PTR_TO_TIMER] = &map_value_types,
> [ARG_KPTR_XCHG_DEST] = &kptr_xchg_dest_types,
> [ARG_PTR_TO_DYNPTR] = &dynptr_types,
> + /* Argument kinds only a kfunc can have. */
> + [ARG_SCALAR] = &scalar_types,
> + [ARG_CONST_SCALAR] = &scalar_types,
> + [ARG_CONST_MEM_SIZE] = &scalar_types,
> + [ARG_PTR_TO_ALLOC_BTF_ID] = &alloc_obj_types,
> + [ARG_PTR_TO_REFCOUNTED_KPTR] = &alloc_obj_or_non_own_ref_types,
> + [ARG_PTR_TO_ITER] = &stack_ptr_types,
> + [ARG_PTR_TO_LIST_HEAD] = &map_value_or_alloc_obj_types,
> + [ARG_PTR_TO_LIST_NODE] = &alloc_obj_or_non_own_ref_types,
> + [ARG_PTR_TO_RB_ROOT] = &map_value_or_alloc_obj_types,
> + [ARG_PTR_TO_RB_NODE] = &alloc_obj_or_non_own_ref_types,
> + [ARG_PTR_TO_RES_SPIN_LOCK] = &map_value_or_alloc_obj_types,
> + [ARG_PTR_TO_WORKQUEUE] = &map_value_types,
> + [ARG_PTR_TO_TASK_WORK] = &map_value_types,
> + [ARG_PTR_TO_IRQ_FLAG] = &stack_ptr_types,
> + [ARG_PTR_TO_ARENA] = &arena_types,
> };
Does ARG_PTR_TO_MEM need to admit allocated objects for kfuncs? Running
check_reg_type() on kfunc arguments makes mem_types the admission gate for
ARG_PTR_TO_MEM, but mem_types lists only PTR_TO_BTF_ID | PTR_TRUSTED among
the BTF-backed register types. Before this commit check_kfunc_args() had no
reg-type test in its ARG_PTR_TO_MEM / ARG_MEM_SIZE cases (the commit
removes tests from ten other cases but adds none here), so a kfunc memory
argument was validated only by check_mem_reg()/check_mem_size_reg() ->
check_helper_mem_access(), which accepts any BTF-ID register:
case PTR_TO_BTF_ID:
return check_ptr_to_btf_access(env, regs, reg, argno, 0,
access_size, access_type, -1);
/* kernel/bpf/verifier.c:7097-7099, switch is on base_type(reg->type) */
Kfunc memory arguments are checked with BPF_READ | BPF_WRITE
(verifier.c:13243 and 13289), and check_ptr_to_btf_access() has an explicit
carve-out that permits exactly those writes for BPF-allocated objects:
/* Writes are permitted with default btf_struct_access for
* program allocated objects (which always have id > 0).
*/
if (atype != BPF_READ && !type_is_ptr_alloc_obj(reg->type)) {
verbose(env, "only read is supported\n");
return -EACCES;
}
/* kernel/bpf/verifier.c:6093-6099 */
check_func_arg_reg_off() likewise enumerates PTR_TO_BTF_ID | MEM_ALLOC and
PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF as register types that legitimately
reach argument checking with a fixed offset (verifier.c:8567-8578). So a
program that does
struct foo *f = bpf_obj_new(typeof(*f));
...
some_kfunc(&f->buf, sizeof(f->buf)); /* void *p, u32 p__sz */
or passes such a pointer to a fixed-size scalar-pointer kfunc argument
(get_kfunc_arg_type() verifier.c:12321, ARG_PTR_TO_MEM | MEM_FIXED_SIZE)
loaded before this commit and is now rejected at check_reg_type() with
-EACCES: "R1 type=ptr_ expected=fp, pkt, pkt_meta, map_key, map_value, mem,
ringbuf_mem, buf, trusted_ptr_, ctx".
Since mem_types already excluded PTR_TO_BTF_ID | MEM_ALLOC for helpers, the
write-to-allocated-object carve-out in check_ptr_to_btf_access() was
reachable from the argument path only through kfuncs; after this commit it
is unreachable from any argument path.
This is a third, undocumented behaviour change. The changelog states "Two
behavior changes fall out of running admission first" and lists only the
ARG_CONST_MEM_SIZE precision fix and the ARG_CONST_MAP_PTR
type_may_be_null() removal. No selftest covers passing an allocated object
as a kfunc memory argument, so the capability is removed silently. Forward
search over the supplied range 8f65640265e8..a490f49b0c4e shows no change
to mem_types. If the narrowing is intended it should be stated in the
changelog (and the now-dead carve-out comment in check_ptr_to_btf_access()
updated); otherwise mem_types needs PTR_TO_BTF_ID | MEM_ALLOC (and the
NON_OWN_REF form).
[ ... ]
> @@ -13002,25 +13015,20 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_call_arg_me
> if (base_type(arg_type) == ARG_PTR_TO_BTF_ID)
> ref_id = *meta->fn->arg_btf_id[i];
>
> - ret = resolve_func_arg_type(env, reg, i, meta, insn_idx, &arg_type, &arg_size);
> + ret = resolve_func_arg_type(env, reg, i, meta, &arg_type, &arg_size);
> if (ret < 0)
> return ret;
> +
> + ret = check_reg_type(env, reg, argno, arg_type, meta);
> + if (ret < 0)
> + return ret;
> +
> ret = check_func_arg_reg_off(env, reg, argno, arg_type);
> if (ret < 0)
> return ret;
>
> switch (base_type(arg_type)) {
> case ARG_CONST_SCALAR:
> - if (reg->type != SCALAR_VALUE) {
> - verbose(env, "%s is not a scalar\n", reg_arg_name(env, argno));
> - bpf_diag_call_arg_fmt(env, insn_idx, argno, func_name,
> - "Pass an integer scalar value for this argument, not a pointer or resource object.",
> - "the kfunc expects an integer scalar, but %s is %s",
> - reg_arg_name(env, argno),
> - bpf_diag_reg_type_plain(env, reg->type));
> - return -EINVAL;
> - }
> -
> ret = process_const_arg(env, reg, argno, meta);
> if (ret < 0) {
> if (ret == -EINVAL)
[ ... ]
> @@ -11845,24 +11874,8 @@ static int resolve_func_arg_type(struct bpf_verifier_env *env,
> ref_t = btf_type_skip_modifiers(btf, ref_id, &ref_id);
> ref_tname = btf_name_by_offset(btf, ref_t->name_off);
>
> - if (!btf_type_is_scalar_struct(env, btf, ref_t)) {
> - enum bpf_reg_type reg2btf_type = lookup_reg2btf_ids(ref_id);
> - const char *expected_type;
> -
> - verbose(env, "%s is %s expected %s %s",
> - reg_arg_name(env, argno), reg_type_str(env, reg->type),
> - btf_type_str(ref_t), ref_tname);
> - if (reg2btf_type != NOT_INIT)
> - verbose(env, " or %s", reg_type_str(env, reg2btf_type));
> - verbose(env, "\n");
> - expected_type = bpf_diag_fmt_btf_type(env, btf, ref_id);
> - bpf_diag_call_arg_fmt(env, insn_idx, argno, meta->func_name,
> - "Pass a verifier-tracked pointer to the expected kernel object type, not a pointer to stack storage or another memory buffer.",
> - "the function expects a pointer to %s, but this argument is %s and cannot be used as that kernel object pointer",
> - expected_type,
> - bpf_diag_reg_type_plain(env, reg->type));
> - return -EINVAL;
> - }
> + if (!btf_type_is_scalar_struct(env, btf, ref_t))
> + return 0;
Does this break existing selftests? The patch deletes the only producer of
the "R1 is fp expected STRUCT prog_test_fail1" diagnostic from
resolve_func_arg_type(), replacing it with a bare `return 0;`. It updates
verifier/calls.c line 79 but leaves three other cases in the same file
still asserting the removed message:
calls.c:34 .errstr = "R1 is fp expected STRUCT prog_test_fail1"
calls.c:49 .errstr = "max struct nesting depth exceeded\nR1 is fp
expected STRUCT prog_test_fail2"
calls.c:64 .errstr = "R1 is fp expected STRUCT prog_test_fail3"
All three are reached: bpf_kfunc_call_test_fail1/2/3 take pointers to
struct prog_test_fail1 (has pointer member), prog_test_fail2 (nesting depth
> 4) and prog_test_fail3 (flexible array), so btf_type_is_scalar_struct()
returns false for each and the removed verbose() used to fire. After the
patch, resolve_func_arg_type() returns 0 with arg_type still
ARG_PTR_TO_BTF_ID; check_reg_type() then rejects R1 (PTR_TO_STACK) against
btf_ptr_types and prints "R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_"
instead. The asserted substrings never appear, so these three test_verifier
cases fail.
These three sites are not fixed anywhere later in the series either: `git
show a490f49b0c4e:tools/testing/selftests/bpf/verifier/calls.c` still
contains all three stale strings, and no commit in 8f65640265e8..a490f49b0c4e
touches verifier/calls.c.
Do the test expectations in other files also need updating? Three more BPF
selftests assert the "is fp expected STRUCT ..." message that this commit
removes from resolve_func_arg_type():
tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c:67
__msg("R1 is fp expected STRUCT cgroup")
tools/testing/selftests/bpf/progs/task_kfunc_failure.c:53
__msg("R1 is fp expected STRUCT task_struct")
tools/testing/selftests/bpf/progs/verifier_vfs_reject.c:31
__msg("R1 is fp expected STRUCT task_struct")
struct cgroup and struct task_struct are not scalar structs, so each of
these used to hit the deleted verbose(); after the patch check_reg_type()
emits "R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_" and the assertions
fail.
This is confirmed by the series itself: commit a490f49b0c4e ("bpf: Check
helper and kfunc arguments in one path"), four commits later, updates
exactly these three lines to __msg("R1 type=fp expected=ptr_, trusted_ptr_,
rcu_ptr_"). Those test-expectation updates belong in this commit, which is
the one that changes the message; as it stands the tree is bisect-broken
for 4 commits (test_progs cgrp_kfunc/task_kfunc/verifier_vfs_reject).
Does this lose test coverage for the ownership check?
rbtree_fail.c:182 and rbtree_fail.c:206 were the only two selftests
asserting the verifier check at kernel/bpf/verifier.c:13183:
verbose(env, "%s can only take non-owning or refcounted bpf_rb_node
pointer\n", func_name);
Both tests invalidate a non-owning ref across bpf_spin_unlock() (the
register becomes SCALAR_VALUE) and then call bpf_rbtree_remove(). With
check_reg_type() now running before the switch, SCALAR_VALUE is rejected by
ARG_PTR_TO_RB_NODE's alloc_obj_or_non_own_ref_types table first, so the
ownership check is no longer reached and the new expectations only assert
the generic register-class error. `grep -r "can only take non-owning or
refcounted" tools/testing/selftests/bpf/` now returns nothing: the check
has zero test coverage after this patch.
Worth double-checking whether that check is still reachable at all. The
only register types that can now reach it are PTR_TO_BTF_ID|MEM_ALLOC,
|NON_OWN_REF and |NON_OWN_REF|MEM_RCU; the NON_OWN_REF forms satisfy
type_is_non_owning_ref(), and a plain owning MEM_ALLOC register whose
reference has been released is invalidated by
release_reference()/mark_reg_invalid(). If no reachable register type
remains, the check is dead and should be dropped rather than left
uncovered; if it is reachable, the two repurposed tests should be kept (or
a replacement added) so the ownership rule stays guarded.
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/33995442755
next prev parent reply other threads:[~2026-09-05 23:23 UTC|newest]
Thread overview: 54+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-05 22:00 [PATCH bpf-next v1 00/22] bpf: Unify helper and kfunc argument checks Amery Hung
2026-09-05 22:00 ` [PATCH bpf-next v1 01/22] bpf: Pass call metadata through shared " Amery Hung
2026-09-05 22:00 ` [PATCH bpf-next v1 02/22] bpf: Address check_func_arg() arguments by argno Amery Hung
2026-09-05 22:44 ` bot+bpf-ci
2026-09-09 17:37 ` Amery Hung
2026-09-05 22:00 ` [PATCH bpf-next v1 03/22] bpf: Only compare func_id against BPF_FUNC_* for helper calls Amery Hung
2026-09-05 22:00 ` [PATCH bpf-next v1 04/22] bpf: Only compare func_id against kfunc BTF IDs for kfunc calls Amery Hung
2026-09-05 22:44 ` bot+bpf-ci
2026-09-09 17:47 ` Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 05/22] bpf: Rename ambiguous function argument types Amery Hung
2026-09-05 23:08 ` bot+bpf-ci
2026-09-09 17:54 ` Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 06/22] bpf: Unify kfunc argument kinds with enum bpf_arg_type Amery Hung
2026-09-05 23:08 ` bot+bpf-ci
2026-09-09 18:04 ` Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 07/22] bpf: Align helper and kfunc ARG_PTR_TO_PROG_AUX handling Amery Hung
2026-09-05 23:08 ` bot+bpf-ci
2026-09-09 18:23 ` Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 08/22] bpf: Classify kfunc arguments the verifier ignores Amery Hung
2026-09-05 22:44 ` bot+bpf-ci
2026-09-09 18:27 ` Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 09/22] bpf: Set OBJ_RELEASE when generating kfunc argument types Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 10/22] bpf: Set MEM_UNINIT and dynptr subtypes when generating kfunc arg types Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 11/22] bpf: Set MEM_RCU when generating kfunc argument types Amery Hung
2026-09-05 22:44 ` bot+bpf-ci
2026-09-09 18:41 ` Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 12/22] bpf: Resolve BTF ID of ARG_PTR_TO_BTF_ID in kfunc bpf_func_proto Amery Hung
2026-09-05 23:08 ` bot+bpf-ci
2026-09-09 20:42 ` Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 13/22] bpf: Resolve ARG_PTR_TO_MEM | MEM_FIXED_SIZE size " Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 14/22] bpf: Consolidate runtime argument type resolution Amery Hung
2026-09-10 21:52 ` Alexei Starovoitov
2026-09-11 21:01 ` Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 15/22] bpf: Consolidate nullable argument validation Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 16/22] bpf: Drop redundant BTF pointer helper write rejection Amery Hung
2026-09-05 23:08 ` bot+bpf-ci
2026-09-09 20:48 ` Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 17/22] bpf: Consolidate helper and kfunc PTR_TO_BTF_ID argument matching Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 18/22] bpf: Admit kfunc argument registers through check_reg_type() Amery Hung
2026-09-05 23:23 ` bot+bpf-ci [this message]
2026-09-10 16:18 ` Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 19/22] selftests/bpf: Test kfunc packet memory direct writes Amery Hung
2026-09-05 22:44 ` bot+bpf-ci
2026-09-11 20:46 ` Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 20/22] bpf: Consolidate function call pkt_access validation Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 21/22] bpf: Consolidate release argument validation Amery Hung
2026-09-05 23:08 ` bot+bpf-ci
2026-09-11 20:47 ` Amery Hung
2026-09-05 22:01 ` [PATCH bpf-next v1 22/22] bpf: Check helper and kfunc arguments in one path Amery Hung
2026-09-05 22:33 ` sashiko-bot
2026-09-11 20:59 ` Amery Hung
2026-09-10 21:53 ` Alexei Starovoitov
2026-09-11 20:55 ` Amery Hung
2026-09-12 3:20 ` [PATCH bpf-next v1 00/22] bpf: Unify helper and kfunc 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=58079fda8b9a98ec66a54e8c1cb80e4eaedf82cc5fda7f8cebef10fb1b4e266d@mail.kernel.org \
--to=bot+bpf-ci@kernel.org \
--cc=alexei.starovoitov@gmail.com \
--cc=ameryhung@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=ihor.solodrai@linux.dev \
--cc=kernel-team@meta.com \
--cc=martin.lau@kernel.org \
--cc=mason@kernel.org \
--cc=memxor@gmail.com \
--cc=yonghong.song@linux.dev \
/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