[PATCH bpf 1/2] bpf: Require referenced or trusted pointer for __arg_trusted arg
From: Yiyang Chen
Date: Mon Oct 05 2026 - 11:23:42 EST
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@xxxxxxxxxxxxxxxxxxxxx>
---
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