summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/bpf
diff options
context:
space:
mode:
authorAmery Hung <ameryhung@gmail.com>2026-09-11 15:04:10 -0700
committerAlexei Starovoitov <ast@kernel.org>2026-09-11 20:16:04 -0700
commit2bd4a975ea5d6394dcaa6c1380653ab68252c9c7 (patch)
tree0edef158faf259aadd329613efa58000f074277e /tools/testing/selftests/bpf
parentb472f03e3141319f44c59b047f5667b29fc5f66e (diff)
downloadlinux-next-2bd4a975ea5d6394dcaa6c1380653ab68252c9c7.tar.gz
linux-next-2bd4a975ea5d6394dcaa6c1380653ab68252c9c7.zip
bpf: Admit kfunc argument registers through check_reg_type()
check_kfunc_args() open-codes exact register-type tests in most of its per-argument cases, duplicating what compatible_reg_types[] already expresses for helpers. This leaves two admission paths and prevents the helper and kfunc loops from converging. Runtime argument resolution now converts a scalar-struct BTF argument to fixed-size memory before register admission. Give the remaining kfunc-only argument kinds compatibility entries and run check_reg_type() once before the per-kind switch. Kfunc memory arguments already accept BPF-allocated objects. Normalize only the local comparison type to PTR_TO_MEM; subsequent memory checks still inspect the original register type. Keep allocated-object forms out of mem_types so helper calls continue through the existing type-mismatch path and retain its diagnostic. For ARG_PTR_TO_BTF_ID, let check_reg_type() admit BTF-backed register types and reject incompatible register classes with its standard diagnostic. Remove the now-unused lookup_reg2btf_ids(). Exact BTF identity and trust requirements remain checked later by process_arg_ptr_to_btf_id(). ARG_IGNORE and ARG_PTR_TO_PROG_AUX remain skipped because the verifier does not read those arguments from the program. Iterator arguments use the stack-pointer table. Graph nodes and ARG_PTR_TO_REFCOUNTED_KPTR share an allocated-object table. It admits owning and borrowed objects, including RCU-protected forms. Their switch cases retain API-specific ownership and BTF-record validation. ARG_PTR_TO_ALLOC_BTF_ID uses a separate table for object-drop arguments. Rename timer_types to map_value_types now that ARG_PTR_TO_WORKQUEUE and ARG_PTR_TO_TASK_WORK share it. Similarly, rename spin_lock_types to map_value_or_alloc_obj_types because graph roots and resource spin locks share its map-value-or-allocated-object admission. Moving admission checks into check_reg_type() must not discard the structured call-argument diagnostics emitted by the individual cases. Add bpf_diag_arg_type_plain() alongside bpf_diag_reg_type_plain() and use it to preserve the existing per-kind Pass suggestions where available. Other argument kinds retain the generic suggestion. The reason continues to report the actual register type and all accepted register types. Two behavior changes fall out of running admission first: - ARG_CONST_MEM_SIZE reaches process_const_arg(), and through it mark_chain_precision(), only after the register is known to be a scalar. Passing a pointer as a __szk argument used to reach backtrack_insn() with a non-scalar and trip the backtracking-misuse verifier bug. - ARG_CONST_MAP_PTR no longer needs its own type_may_be_null() test, because check_reg_type() compares whole register types. Every kfunc argument that is not explicitly ignored now passes through check_reg_type(), followed by the common register-offset check in the same order as a helper argument. Signed-off-by: Amery Hung <ameryhung@gmail.com> Link: https://lore.kernel.org/r/20260911220415.1396439-19-ameryhung@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'tools/testing/selftests/bpf')
-rw-r--r--tools/testing/selftests/bpf/prog_tests/kfunc_call.c2
-rw-r--r--tools/testing/selftests/bpf/progs/arena_kfunc.c2
-rw-r--r--tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c2
-rw-r--r--tools/testing/selftests/bpf/progs/cpumask_failure.c2
-rw-r--r--tools/testing/selftests/bpf/progs/irq.c4
-rw-r--r--tools/testing/selftests/bpf/progs/iters.c6
-rw-r--r--tools/testing/selftests/bpf/progs/iters_testmod.c3
-rw-r--r--tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c3
-rw-r--r--tools/testing/selftests/bpf/progs/rbtree_fail.c4
-rw-r--r--tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c9
-rw-r--r--tools/testing/selftests/bpf/progs/res_spin_lock_fail.c2
-rw-r--r--tools/testing/selftests/bpf/progs/stream_fail.c2
-rw-r--r--tools/testing/selftests/bpf/progs/task_kfunc_failure.c2
-rw-r--r--tools/testing/selftests/bpf/progs/task_work_fail.c2
-rw-r--r--tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c2
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_vfs_reject.c2
-rw-r--r--tools/testing/selftests/bpf/progs/wq_failures.c4
-rw-r--r--tools/testing/selftests/bpf/verifier/calls.c8
18 files changed, 29 insertions, 32 deletions
diff --git a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c
index 2b39cc1b09f9..0063e60d6f2f 100644
--- a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c
+++ b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c
@@ -70,7 +70,7 @@ static struct kfunc_test_params kfunc_tests[] = {
TC_FAIL(kfunc_call_test_get_mem_fail_oversized, 0, "allocation size exceeds u32 max"),
TC_FAIL(kfunc_call_test_get_mem_fail_not_const, 0, "is not a const"),
TC_FAIL(kfunc_call_test_mem_acquire_fail, 0, "acquire kernel function does not return PTR_TO_BTF_ID"),
- TC_FAIL(kfunc_call_test_pointer_arg_type_mismatch, 0, "R1 expected pointer to ctx, but got scalar"),
+ TC_FAIL(kfunc_call_test_pointer_arg_type_mismatch, 0, "R1 type=scalar expected=ctx"),
TC_FAIL(kfunc_call_test_spin_lock_unsafe, 0, "function calls are not allowed while holding a lock"),
/* success cases */
diff --git a/tools/testing/selftests/bpf/progs/arena_kfunc.c b/tools/testing/selftests/bpf/progs/arena_kfunc.c
index 50609f3b0564..6578cf12fa27 100644
--- a/tools/testing/selftests/bpf/progs/arena_kfunc.c
+++ b/tools/testing/selftests/bpf/progs/arena_kfunc.c
@@ -205,7 +205,7 @@ int arena_arg_no_arena(void *ctx)
SEC("syscall")
__arch_x86_64
__arch_arm64
-__failure __msg("is not a pointer to arena or scalar")
+__failure __msg("R1 type=fp expected=arena, scalar")
int arena_arg_bad_reg(void *ctx)
{
u64 buf = 0;
diff --git a/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c b/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c
index efe7bcae70f8..a7c8c765a98d 100644
--- a/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c
+++ b/tools/testing/selftests/bpf/progs/cgrp_kfunc_failure.c
@@ -64,7 +64,7 @@ int BPF_PROG(cgrp_kfunc_acquire_no_null_check, struct cgroup *cgrp, const char *
}
SEC("tp_btf/cgroup_mkdir")
-__failure __msg("R1 is fp expected STRUCT cgroup")
+__failure __msg("R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_")
int BPF_PROG(cgrp_kfunc_acquire_fp, struct cgroup *cgrp, const char *path)
{
struct cgroup *acquired, *stack_cgrp = (struct cgroup *)&path;
diff --git a/tools/testing/selftests/bpf/progs/cpumask_failure.c b/tools/testing/selftests/bpf/progs/cpumask_failure.c
index 6d730535eb95..76a3cba6f23c 100644
--- a/tools/testing/selftests/bpf/progs/cpumask_failure.c
+++ b/tools/testing/selftests/bpf/progs/cpumask_failure.c
@@ -243,7 +243,7 @@ int BPF_PROG(test_populate_invalid_destination, struct task_struct *task, u64 cl
}
SEC("tp_btf/task_newtask")
-__failure __msg("leads to invalid memory access")
+__failure __msg("R2 type=scalar expected=fp")
int BPF_PROG(test_populate_invalid_source, struct task_struct *task, u64 clone_flags)
{
void *garbage = (void *)0x123456;
diff --git a/tools/testing/selftests/bpf/progs/irq.c b/tools/testing/selftests/bpf/progs/irq.c
index a4a007866a33..53df6d248e26 100644
--- a/tools/testing/selftests/bpf/progs/irq.c
+++ b/tools/testing/selftests/bpf/progs/irq.c
@@ -15,7 +15,7 @@ struct bpf_res_spin_lock lockA __hidden SEC(".data.A");
struct bpf_res_spin_lock lockB __hidden SEC(".data.B");
SEC("?tc")
-__failure __msg("R1 doesn't point to an irq flag on stack")
+__failure __msg("R1 type=map_value expected=fp")
int irq_save_bad_arg(struct __sk_buff *ctx)
{
bpf_local_irq_save(&global_flags);
@@ -23,7 +23,7 @@ int irq_save_bad_arg(struct __sk_buff *ctx)
}
SEC("?tc")
-__failure __msg("R1 doesn't point to an irq flag on stack")
+__failure __msg("R1 type=map_value expected=fp")
int irq_restore_bad_arg(struct __sk_buff *ctx)
{
bpf_local_irq_restore(&global_flags);
diff --git a/tools/testing/selftests/bpf/progs/iters.c b/tools/testing/selftests/bpf/progs/iters.c
index c6699159dacd..65d4c6e01f93 100644
--- a/tools/testing/selftests/bpf/progs/iters.c
+++ b/tools/testing/selftests/bpf/progs/iters.c
@@ -1688,7 +1688,7 @@ int iter_subprog_check_stacksafe(const void *ctx)
struct bpf_iter_num global_it;
SEC("raw_tp")
-__failure __msg("R1 expected pointer to an iterator on stack")
+__failure __msg("R1 type=map_value expected=fp")
int iter_new_bad_arg(const void *ctx)
{
bpf_iter_num_new(&global_it, 0, 1);
@@ -1696,7 +1696,7 @@ int iter_new_bad_arg(const void *ctx)
}
SEC("raw_tp")
-__failure __msg("R1 expected pointer to an iterator on stack")
+__failure __msg("R1 type=map_value expected=fp")
int iter_next_bad_arg(const void *ctx)
{
bpf_iter_num_next(&global_it);
@@ -1704,7 +1704,7 @@ int iter_next_bad_arg(const void *ctx)
}
SEC("raw_tp")
-__failure __msg("R1 expected pointer to an iterator on stack")
+__failure __msg("R1 type=map_value expected=fp")
int iter_destroy_bad_arg(const void *ctx)
{
bpf_iter_num_destroy(&global_it);
diff --git a/tools/testing/selftests/bpf/progs/iters_testmod.c b/tools/testing/selftests/bpf/progs/iters_testmod.c
index 5a3ff65e8234..f65cc9766633 100644
--- a/tools/testing/selftests/bpf/progs/iters_testmod.c
+++ b/tools/testing/selftests/bpf/progs/iters_testmod.c
@@ -105,8 +105,7 @@ out:
}
SEC("raw_tp/sys_enter")
-__failure __msg("R1 cannot write into rdonly_mem")
-/* Message should not be 'R1 cannot write into rdonly_trusted_mem' */
+__failure __msg("R1 type=rdonly_mem expected=fp")
int iter_next_ptr_mem_not_trusted(const void *ctx)
{
struct bpf_iter_num num_it;
diff --git a/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c b/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c
index 3e0d4f687aaa..23019023511a 100644
--- a/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c
+++ b/tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c
@@ -118,8 +118,7 @@ int atomic_rmw_not_ok(void *ctx)
SEC("socket")
__failure
-__msg("invalid access to memory, mem_size=0 off=0 size=4")
-__msg("R1 min value is outside of the allowed memory range")
+__msg("R1 type=rdonly_untrusted_mem expected=fp")
int kfunc_param_not_ok(void *ctx)
{
int *p;
diff --git a/tools/testing/selftests/bpf/progs/rbtree_fail.c b/tools/testing/selftests/bpf/progs/rbtree_fail.c
index 4504608196ab..08709f23ec0f 100644
--- a/tools/testing/selftests/bpf/progs/rbtree_fail.c
+++ b/tools/testing/selftests/bpf/progs/rbtree_fail.c
@@ -180,7 +180,7 @@ err_out:
}
SEC("?tc")
-__failure __msg("bpf_rbtree_remove can only take non-owning or refcounted bpf_rb_node pointer")
+__failure __msg("R2 type=scalar expected=ptr_, rcu_ptr_, ptr_, rcu_ptr_")
long rbtree_api_add_release_unlock_escape(void *ctx)
{
struct node_data *n;
@@ -204,7 +204,7 @@ long rbtree_api_add_release_unlock_escape(void *ctx)
}
SEC("?tc")
-__failure __msg("bpf_rbtree_remove can only take non-owning or refcounted bpf_rb_node pointer")
+__failure __msg("R2 type=scalar expected=ptr_, rcu_ptr_, ptr_, rcu_ptr_")
long rbtree_api_first_release_unlock_escape(void *ctx)
{
struct bpf_rb_node *res;
diff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
index 338e43822ffe..e80f78fae227 100644
--- a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
+++ b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
@@ -118,8 +118,8 @@ long refcount_acquire_maybe_null(void *ctx)
}
SEC("?tc")
-__failure __msg("R1 is neither owning or non-owning ref")
-__msg("expects a pointer to a BPF-managed refcounted object, but R1 is a context pointer")
+__failure __msg("R1 type=ctx expected=ptr_, rcu_ptr_, ptr_, rcu_ptr_")
+__msg("type ctx, but this argument accepts ptr_, rcu_ptr_, ptr_, rcu_ptr_")
long refcount_acquire_non_object(void *ctx)
{
return bpf_refcount_acquire(ctx) != NULL;
@@ -159,8 +159,7 @@ long refcount_acquire_rcu_map_kptr_unchecked_drop(void *ctx)
SEC("?syscall")
__failure
-__msg("bpf_rbtree_remove can only take non-owning or refcounted "
- "bpf_rb_node pointer")
+__msg("R2 type=untrusted_ptr_ expected=ptr_, rcu_ptr_, ptr_, rcu_ptr_")
long rbtree_remove_after_rcu_unlock(void *ctx)
{
struct map_value_rcu_graph *mapval;
@@ -190,7 +189,7 @@ long rbtree_remove_after_rcu_unlock(void *ctx)
}
SEC("?syscall")
-__failure __msg("R1 is neither owning or non-owning ref")
+__failure __msg("R1 type=untrusted_ptr_ expected=ptr_, rcu_ptr_, ptr_, rcu_ptr_")
long refcount_acquire_after_rcu_unlock(void *ctx)
{
struct map_value_refcount_only *mapval;
diff --git a/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c b/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c
index 330682a88c16..8fd591bd1f6c 100644
--- a/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c
+++ b/tools/testing/selftests/bpf/progs/res_spin_lock_fail.c
@@ -24,7 +24,7 @@ struct bpf_spin_lock lock __hidden SEC(".data.A");
struct bpf_res_spin_lock res_lock __hidden SEC(".data.B");
SEC("?tc")
-__failure __msg("point to map value or allocated object")
+__failure __msg("R1 type=untrusted_ptr_ expected=map_value, ptr_")
int res_spin_lock_arg(struct __sk_buff *ctx)
{
struct arr_elem *elem;
diff --git a/tools/testing/selftests/bpf/progs/stream_fail.c b/tools/testing/selftests/bpf/progs/stream_fail.c
index 21428bb1ee59..10ebb4a7f105 100644
--- a/tools/testing/selftests/bpf/progs/stream_fail.c
+++ b/tools/testing/selftests/bpf/progs/stream_fail.c
@@ -23,7 +23,7 @@ int stream_vprintk_scalar_arg(void *ctx)
}
SEC("syscall")
-__failure __msg("R2 doesn't point to a const string")
+__failure __msg("R2 type=ctx expected=map_value")
int stream_vprintk_string_arg(void *ctx)
{
bpf_stream_vprintk(BPF_STDOUT, ctx, NULL, 0);
diff --git a/tools/testing/selftests/bpf/progs/task_kfunc_failure.c b/tools/testing/selftests/bpf/progs/task_kfunc_failure.c
index 9979766d4d74..404f7f9d7150 100644
--- a/tools/testing/selftests/bpf/progs/task_kfunc_failure.c
+++ b/tools/testing/selftests/bpf/progs/task_kfunc_failure.c
@@ -50,7 +50,7 @@ int BPF_PROG(task_kfunc_acquire_untrusted, struct task_struct *task, u64 clone_f
}
SEC("tp_btf/task_newtask")
-__failure __msg("R1 is fp expected STRUCT task_struct")
+__failure __msg("R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_")
int BPF_PROG(task_kfunc_acquire_fp, struct task_struct *task, u64 clone_flags)
{
struct task_struct *acquired, *stack_task = (struct task_struct *)&clone_flags;
diff --git a/tools/testing/selftests/bpf/progs/task_work_fail.c b/tools/testing/selftests/bpf/progs/task_work_fail.c
index 3186e7b4b24e..bc56bdaca780 100644
--- a/tools/testing/selftests/bpf/progs/task_work_fail.c
+++ b/tools/testing/selftests/bpf/progs/task_work_fail.c
@@ -58,7 +58,7 @@ int mismatch_map(struct pt_regs *args)
}
SEC("perf_event")
-__failure __msg("R2 doesn't point to a map value")
+__failure __msg("R2 type=fp expected=map_value")
int no_map_task_work(struct pt_regs *args)
{
struct task_struct *task;
diff --git a/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c b/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c
index bf48fc43c7ab..f7a83e502454 100644
--- a/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c
+++ b/tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c
@@ -40,7 +40,7 @@ int BPF_PROG(not_valid_dynptr, int cmd, union bpf_attr *attr, unsigned int size,
}
SEC("?lsm.s/bpf")
-__failure __msg("R1 expected pointer to stack or const struct bpf_dynptr")
+__failure __msg("R1 type=map_value expected=fp, dynptr_ptr")
int BPF_PROG(not_ptr_to_stack, int cmd, union bpf_attr *attr, unsigned int size, bool kernel)
{
static struct bpf_dynptr val;
diff --git a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c
index ff08aa75d6f7..2cea3d9c3647 100644
--- a/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c
+++ b/tools/testing/selftests/bpf/progs/verifier_vfs_reject.c
@@ -28,7 +28,7 @@ int BPF_PROG(get_task_exe_file_kfunc_null)
}
SEC("lsm.s/inode_getxattr")
-__failure __msg("R1 is fp expected STRUCT task_struct")
+__failure __msg("R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_")
int BPF_PROG(get_task_exe_file_kfunc_fp)
{
u64 x;
diff --git a/tools/testing/selftests/bpf/progs/wq_failures.c b/tools/testing/selftests/bpf/progs/wq_failures.c
index 32dc8827e128..bd30217579d4 100644
--- a/tools/testing/selftests/bpf/progs/wq_failures.c
+++ b/tools/testing/selftests/bpf/progs/wq_failures.c
@@ -48,7 +48,7 @@ __log_level(2)
__flag(BPF_F_TEST_STATE_FREQ)
__failure
__msg(": (85) call bpf_wq_init#") /* anchor message */
-__msg("pointer in R2 isn't map pointer")
+__msg("R2 type=fp expected=map_ptr")
long test_wq_init_nomap(void *ctx)
{
struct bpf_wq *wq;
@@ -98,7 +98,7 @@ __failure
* is a correct bpf_wq pointer.
*/
__msg(": (85) call bpf_wq_set_callback#") /* anchor message */
-__msg("R1 doesn't point to a map value")
+__msg("R1 type=fp expected=map_value")
long test_wrong_wq_pointer(void *ctx)
{
int key = 0;
diff --git a/tools/testing/selftests/bpf/verifier/calls.c b/tools/testing/selftests/bpf/verifier/calls.c
index d730215e520b..8b94b87135bc 100644
--- a/tools/testing/selftests/bpf/verifier/calls.c
+++ b/tools/testing/selftests/bpf/verifier/calls.c
@@ -31,7 +31,7 @@
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = REJECT,
- .errstr = "R1 is fp expected STRUCT prog_test_fail1",
+ .errstr = "R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_",
.fixup_kfunc_btf_id = {
{ "bpf_kfunc_call_test_fail1", 2 },
},
@@ -46,7 +46,7 @@
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = REJECT,
- .errstr = "max struct nesting depth exceeded\nR1 is fp expected STRUCT prog_test_fail2",
+ .errstr = "max struct nesting depth exceeded\nR1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_",
.fixup_kfunc_btf_id = {
{ "bpf_kfunc_call_test_fail2", 2 },
},
@@ -61,7 +61,7 @@
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = REJECT,
- .errstr = "R1 is fp expected STRUCT prog_test_fail3",
+ .errstr = "R1 type=fp expected=ptr_, trusted_ptr_, rcu_ptr_",
.fixup_kfunc_btf_id = {
{ "bpf_kfunc_call_test_fail3", 2 },
},
@@ -76,7 +76,7 @@
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = REJECT,
- .errstr = "R1 expected pointer to ctx, but got fp",
+ .errstr = "R1 type=fp expected=ctx",
.fixup_kfunc_btf_id = {
{ "bpf_kfunc_call_test_pass_ctx", 2 },
},