All of lore.kernel.org
 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 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.