* [PATCH bpf 0/2] bpf: Require referenced or trusted pointer for __arg_trusted arg
@ 2026-10-05 15:12 Yiyang Chen
2026-10-05 15:12 ` [PATCH bpf 1/2] " Yiyang Chen
2026-10-05 15:12 ` [PATCH bpf 2/2] selftests/bpf: Cover non-trusted pointer to __arg_trusted subprog arg Yiyang Chen
0 siblings, 2 replies; 5+ messages in thread
From: Yiyang Chen @ 2026-10-05 15:12 UTC (permalink / raw)
To: Eduard Zingerman, Daniel Borkmann, Alexei Starovoitov,
Andrii Nakryiko, Kumar Kartikeya Dwivedi
Cc: Yonghong Song, Ihor Solodrai, Shuah Khan, Jiri Olsa,
linux-kselftest, linux-kernel, John Fastabend, Emil Tsalapatis,
bpf, Song Liu, Martin KaFai Lau
A global subprogram parameter tagged __arg_trusted is specified to accept
only the PTR_TRUSTED flavor of PTR_TO_BTF_ID, but the call-site check also
accepts a bare PTR_TO_BTF_ID and an MEM_RCU one.
check_reg_type() resolves the accepted types from the base argument type
alone without consulting arg_type's PTR_TRUSTED bit, and the trusted/RCU
enforcement in check_func_arg() is gated on is_kfunc(meta) so it never runs
for a subprogram call. A caller can therefore pass a pointer that is not
trusted and the callee is verified as holding PTR_TRUSTED, which makes the
dereference a raw load instead of a BPF_PROBE_MEM probe and lets the callee
pass the pointer on to a kfunc that would have rejected it at the original
call site.
Reject a PTR_TO_BTF_ID that is neither referenced nor trusted when the
argument is marked PTR_TRUSTED. A referenced register is accepted, as in
is_trusted_reg(). PTR_MAYBE_NULL is not counted as unsafe when __arg_nullable
declares it, so trusted-and-nullable arguments keep working. The kfunc path
is unchanged.
Yiyang Chen (2):
bpf: Require referenced or trusted pointer for __arg_trusted arg
selftests/bpf: Cover non-trusted pointer to __arg_trusted subprog arg
kernel/bpf/verifier.c | 21 ++++++++++++
.../selftests/bpf/progs/verifier_global_ptr_args.c | 40 ++++++++++++++++++++++
2 files changed, 61 insertions(+)
base-commit: d82cbceca49252bb0cd695326af8206c734e2744
--
2.34.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH bpf 1/2] bpf: Require referenced or trusted pointer for __arg_trusted arg 2026-10-05 15:12 [PATCH bpf 0/2] bpf: Require referenced or trusted pointer for __arg_trusted arg Yiyang Chen @ 2026-10-05 15:12 ` Yiyang Chen 2026-10-05 15:26 ` sashiko-bot 2026-10-05 22:50 ` Amery Hung 2026-10-05 15:12 ` [PATCH bpf 2/2] selftests/bpf: Cover non-trusted pointer to __arg_trusted subprog arg Yiyang Chen 1 sibling, 2 replies; 5+ messages in thread From: Yiyang Chen @ 2026-10-05 15:12 UTC (permalink / raw) To: Eduard Zingerman, Daniel Borkmann, Alexei Starovoitov, Andrii Nakryiko, Kumar Kartikeya Dwivedi Cc: Yonghong Song, Ihor Solodrai, Shuah Khan, Jiri Olsa, linux-kselftest, linux-kernel, John Fastabend, Emil Tsalapatis, bpf, Song Liu, Martin KaFai Lau A global subprogram parameter tagged __arg_trusted is documented to accept only the PTR_TRUSTED flavor of PTR_TO_BTF_ID, but the call-site check also accepts a bare PTR_TO_BTF_ID and an MEM_RCU one. check_reg_type() resolves the accepted set from the base argument type alone and compares only MEM_RDONLY and PTR_MAYBE_NULL, so the PTR_TRUSTED bit of arg_type is never consulted. The trusted/RCU enforcement in check_func_arg() is gated on is_kfunc(meta), which is false for a subprogram call, so that block is skipped for __arg_trusted arguments. The callee is then validated with PTR_TRUSTED set on the register while the caller passed a pointer that is neither referenced nor trusted. bpf_may_fault_on_deref() is false for PTR_TRUSTED, so the dereference becomes a raw load instead of a BPF_PROBE_MEM probe, is_trusted_reg() kfuncs accept the pointer, and the callee can pass it on to a kfunc that would have rejected it at the original call site. Reject a PTR_TO_BTF_ID that is neither referenced nor trusted when the argument is marked PTR_TRUSTED. A referenced register is accepted, as in is_trusted_reg(). PTR_MAYBE_NULL is not counted as an unsafe modifier when __arg_nullable declares it, so trusted-and-nullable arguments keep working. The kfunc path is unchanged. Fixes: e2b3c4ff5d183da6d1863c2321413406a2752e7a ("bpf: add __arg_trusted global func arg tag") Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn> --- kernel/bpf/verifier.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index fd3c0206bd67d..fe5edbef85a16 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -9597,6 +9597,27 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 p } } + /* A __arg_trusted argument requires a referenced or trusted + * pointer. btf_ptr_types also matches a bare PTR_TO_BTF_ID and + * an MEM_RCU one, but neither is referenced or trusted, so the + * callee would be verified with PTR_TRUSTED while the caller + * passed something that is not. PTR_MAYBE_NULL is not counted + * as unsafe when __arg_nullable declares it, because + * bpf_type_has_unsafe_modifiers() treats that flag as unsafe. + */ + if ((arg_type & PTR_TRUSTED) && base_type(reg->type) == PTR_TO_BTF_ID && + !reg_is_referenced(env, reg)) { + u32 flags = type_flag(reg->type); + + if (!(flags & BPF_REG_TRUSTED_MODIFIERS) || + (flags & ~(BPF_REG_TRUSTED_MODIFIERS | + (arg_type & PTR_MAYBE_NULL)))) { + verbose(env, "%s must be referenced or trusted\n", + reg_arg_name(env, argno)); + return -EINVAL; + } + } + if (is_kfunc(meta) && (!is_trusted_reg(env, reg) || bpf_type_has_unsafe_modifiers(reg->type))) { if (!(arg_type & MEM_RCU)) { -- 2.43.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH bpf 1/2] bpf: Require referenced or trusted pointer for __arg_trusted arg 2026-10-05 15:12 ` [PATCH bpf 1/2] " Yiyang Chen @ 2026-10-05 15:26 ` sashiko-bot 2026-10-05 22:50 ` Amery Hung 1 sibling, 0 replies; 5+ messages in thread From: sashiko-bot @ 2026-10-05 15:26 UTC (permalink / raw) To: Yiyang Chen; +Cc: bpf Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] bpf: wrong multi-line comment style in check_func_arg() -- commit 66de311fe0f463c286064b3e009d6635674afd83 Author: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn> bpf: Require referenced or trusted pointer for __arg_trusted arg This commit modifies the verifier to reject PTR_TO_BTF_ID pointers that are neither referenced nor trusted for arguments marked PTR_TRUSTED. It fixes an issue where a bare PTR_TO_BTF_ID or MEM_RCU could bypass checks in subprogram calls. > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index fd3c0206bd67d..fe5edbef85a16 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -9597,6 +9597,27 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 p > } > } > > + /* A __arg_trusted argument requires a referenced or trusted > + * pointer. btf_ptr_types also matches a bare PTR_TO_BTF_ID and [Severity: Low] This isn't a bug, but does this violate the BPF subsystem multi-line comment style? The BPF guideline requires the opening /* to be on its own line for multi-line comments. > + * an MEM_RCU one, but neither is referenced or trusted, so the > + * callee would be verified with PTR_TRUSTED while the caller > + * passed something that is not. PTR_MAYBE_NULL is not counted > + * as unsafe when __arg_nullable declares it, because > + * bpf_type_has_unsafe_modifiers() treats that flag as unsafe. > + */ > + if ((arg_type & PTR_TRUSTED) && base_type(reg->type) == PTR_TO_BTF_ID && > + !reg_is_referenced(env, reg)) { -- Sashiko AI review · https://sashiko.dev/#/patchset/20261005-a3-arg-trusted-v4-v1-0-50ee0268fd39@mails.tsinghua.edu.cn?part=1 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH bpf 1/2] bpf: Require referenced or trusted pointer for __arg_trusted arg 2026-10-05 15:12 ` [PATCH bpf 1/2] " Yiyang Chen 2026-10-05 15:26 ` sashiko-bot @ 2026-10-05 22:50 ` Amery Hung 1 sibling, 0 replies; 5+ messages in thread From: Amery Hung @ 2026-10-05 22:50 UTC (permalink / raw) To: Yiyang Chen Cc: Eduard Zingerman, Daniel Borkmann, Alexei Starovoitov, Andrii Nakryiko, Kumar Kartikeya Dwivedi, Yonghong Song, Ihor Solodrai, Shuah Khan, Jiri Olsa, linux-kselftest, linux-kernel, John Fastabend, Emil Tsalapatis, bpf, Song Liu, Martin KaFai Lau On Mon, Oct 5, 2026 at 8:23 AM Yiyang Chen <chenyy23@mails.tsinghua.edu.cn> wrote: > > A global subprogram parameter tagged __arg_trusted is documented to > accept only the PTR_TRUSTED flavor of PTR_TO_BTF_ID, but the call-site > check also accepts a bare PTR_TO_BTF_ID and an MEM_RCU one. > > check_reg_type() resolves the accepted set from the base argument type > alone and compares only MEM_RDONLY and PTR_MAYBE_NULL, so the PTR_TRUSTED > bit of arg_type is never consulted. The trusted/RCU enforcement in > check_func_arg() is gated on is_kfunc(meta), which is false for a > subprogram call, so that block is skipped for __arg_trusted arguments. > > The callee is then validated with PTR_TRUSTED set on the register while > the caller passed a pointer that is neither referenced nor trusted. > bpf_may_fault_on_deref() is false for PTR_TRUSTED, so the dereference > becomes a raw load instead of a BPF_PROBE_MEM probe, is_trusted_reg() > kfuncs accept the pointer, and the callee can pass it on to a kfunc that > would have rejected it at the original call site. > > Reject a PTR_TO_BTF_ID that is neither referenced nor trusted when the > argument is marked PTR_TRUSTED. A referenced register is accepted, as in > is_trusted_reg(). PTR_MAYBE_NULL is not counted as an unsafe modifier > when __arg_nullable declares it, so trusted-and-nullable arguments keep > working. The kfunc path is unchanged. > > Fixes: e2b3c4ff5d183da6d1863c2321413406a2752e7a ("bpf: add __arg_trusted global func arg tag") > Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn> > --- > kernel/bpf/verifier.c | 21 +++++++++++++++++++++ > 1 file changed, 21 insertions(+) > > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index fd3c0206bd67d..fe5edbef85a16 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -9597,6 +9597,27 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, u32 slot, u32 p > } > } > > + /* A __arg_trusted argument requires a referenced or trusted > + * pointer. btf_ptr_types also matches a bare PTR_TO_BTF_ID and > + * an MEM_RCU one, but neither is referenced or trusted, so the > + * callee would be verified with PTR_TRUSTED while the caller > + * passed something that is not. PTR_MAYBE_NULL is not counted > + * as unsafe when __arg_nullable declares it, because > + * bpf_type_has_unsafe_modifiers() treats that flag as unsafe. > + */ > + if ((arg_type & PTR_TRUSTED) && base_type(reg->type) == PTR_TO_BTF_ID && > + !reg_is_referenced(env, reg)) { > + u32 flags = type_flag(reg->type); > + > + if (!(flags & BPF_REG_TRUSTED_MODIFIERS) || > + (flags & ~(BPF_REG_TRUSTED_MODIFIERS | > + (arg_type & PTR_MAYBE_NULL)))) { > + verbose(env, "%s must be referenced or trusted\n", > + reg_arg_name(env, argno)); > + return -EINVAL; > + } > + } > + Could we avoid adding a second provenance check and make the existing kfunc check contract-driven instead? Kfunc ARG_PTR_TO_BTF_ID arguments implicitly require trusted or referenced provenance through the is_kfunc(meta) condition. Global subprogs express the same requirement explicitly with PTR_TRUSTED. Likewise, __nullable and __arg_nullable permit PTR_MAYBE_NULL, which should not by itself make the provenance invalid. First, encode the kfunc requirement in its generated prototype: if (base_type(arg_type) == ARG_PTR_TO_BTF_ID) { arg_type |= PTR_TRUSTED; /* MEM_RCU denotes an accepted alternative provenance. */ if (is_kfunc_rcu(meta)) arg_type |= MEM_RCU; } The common check can then be driven entirely by the argument contract: reg_type = reg->type & ~(arg_type & PTR_MAYBE_NULL); if ((arg_type & PTR_TRUSTED) && (!is_trusted_reg_type(env, reg, reg_type) || bpf_type_has_unsafe_modifiers(reg_type))) { if (!(arg_type & MEM_RCU)) { /* must be referenced or trusted */ return -EINVAL; } if (!is_rcu_reg(reg)) { /* must be an RCU pointer */ return -EINVAL; } } is_trusted_reg_type() would contain the existing is_trusted_reg() logic, but use the supplied normalized type for its type and modifier checks while still using the original register ID for reference lookup. resolve_func_arg_type() should continue dropping PTR_TRUSTED when it changes ARG_PTR_TO_BTF_ID into ARG_PTR_TO_MEM; that is a different, fixed-size memory-buffer contract. This also lets a kfunc __nullable argument accept PTR_TRUSTED | PTR_MAYBE_NULL, as its existing contract specifies. Please add corresponding kfunc coverage and adjust the claim that the kfunc path is unchanged. > if (is_kfunc(meta) && (!is_trusted_reg(env, reg) || > bpf_type_has_unsafe_modifiers(reg->type))) { > if (!(arg_type & MEM_RCU)) { > > -- > 2.43.0 > > ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH bpf 2/2] selftests/bpf: Cover non-trusted pointer to __arg_trusted subprog arg 2026-10-05 15:12 [PATCH bpf 0/2] bpf: Require referenced or trusted pointer for __arg_trusted arg Yiyang Chen 2026-10-05 15:12 ` [PATCH bpf 1/2] " Yiyang Chen @ 2026-10-05 15:12 ` Yiyang Chen 1 sibling, 0 replies; 5+ messages in thread From: Yiyang Chen @ 2026-10-05 15:12 UTC (permalink / raw) To: Eduard Zingerman, Daniel Borkmann, Alexei Starovoitov, Andrii Nakryiko, Kumar Kartikeya Dwivedi Cc: Yonghong Song, Ihor Solodrai, Shuah Khan, Jiri Olsa, linux-kselftest, linux-kernel, John Fastabend, Emil Tsalapatis, bpf, Song Liu, Martin KaFai Lau verifier_global_ptr_args.c already covers passing an untrusted pointer to a __arg_trusted argument, which is rejected by the register type match. It does not cover the bare PTR_TO_BTF_ID or MEM_RCU flavors, both of which the type match accepts. Add two cases. The first walks task_struct->last_wakee out of a trusted current task and passes the result to a __arg_trusted subprogram parameter; the field has no __rcu tag and is not in BTF_TYPE_SAFE_RCU(task_struct), so the load yields a bare PTR_TO_BTF_ID. The second passes task_struct->real_parent, which is __rcu and on BTF_TYPE_SAFE_RCU(task_struct), so the load yields PTR_TO_BTF_ID | MEM_RCU. Both calls are expected to be rejected with "must be referenced or trusted". Signed-off-by: Yiyang Chen <chenyy23@mails.tsinghua.edu.cn> --- .../selftests/bpf/progs/verifier_global_ptr_args.c | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c index 03507eeae3cb3..ec042f91bcf20 100644 --- a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c +++ b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c @@ -289,6 +289,46 @@ __weak int subprog_void_untrusted(void *p __arg_untrusted) return *(int *)p; } +__weak int subprog_trusted_bare(struct task_struct *task __arg_trusted) +{ + return task->pid; +} + +SEC("tp_btf/task_newtask") +__failure +__msg("R1 must be referenced or trusted") +__msg("Caller passes invalid args into func#{{.*}} ('subprog_trusted_bare')") +int bare_to_trusted(void *ctx) +{ + struct task_struct *cur = bpf_get_current_task_btf(); + struct task_struct *wakee; + + if (!cur) + return 0; + wakee = cur->last_wakee; + if (!wakee) + return 0; + return subprog_trusted_bare(wakee); +} + +/* + * real_parent is __rcu and on BTF_TYPE_SAFE_RCU(task_struct), so the load + * yields PTR_TO_BTF_ID | MEM_RCU. That is neither referenced nor trusted and + * must not satisfy __arg_trusted. + */ +SEC("tp_btf/task_newtask") +__failure +__msg("R1 must be referenced or trusted") +__msg("Caller passes invalid args into func#{{.*}} ('subprog_trusted_task_nullable')") +int memrcu_to_trusted(void *ctx) +{ + struct task_struct *cur = bpf_get_current_task_btf(); + + if (!cur) + return 0; + return subprog_trusted_task_nullable(cur->real_parent); +} + __weak int subprog_char_untrusted(char *p __arg_untrusted) { return *(int *)p; -- 2.43.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-10-05 22:51 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-05 15:12 [PATCH bpf 0/2] bpf: Require referenced or trusted pointer for __arg_trusted arg Yiyang Chen 2026-10-05 15:12 ` [PATCH bpf 1/2] " Yiyang Chen 2026-10-05 15:26 ` sashiko-bot 2026-10-05 22:50 ` Amery Hung 2026-10-05 15:12 ` [PATCH bpf 2/2] selftests/bpf: Cover non-trusted pointer to __arg_trusted subprog arg Yiyang Chen
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.