* [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
* [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
* 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
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox