BPF List
 help / color / mirror / Atom feed
* [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