Merge branch 'bpf-enforce-btf-pointer-write-checks-for-global-args'

Nuoqi Gui says:

====================
bpf: Enforce BTF pointer write checks for global args

check_mem_reg() verifies both read and write access when a caller passes
memory into a global subprogram. For PTR_TO_BTF_ID callers,
check_helper_mem_access() currently always checks the access as BPF_READ.

That lets a tracing program pass a task_struct field pointer to a global
subprogram argument typed as writable memory. The direct field store is rejected
with "only read is supported", but the callee is validated with a generic
writable PTR_TO_MEM argument and can store through it.

Forward the requested access type into the PTR_TO_BTF_ID helper-access path and
add verifier coverage for the global-subprogram argument case.

Validation (tested on bpf-next 8496d9020f):

  Without this series:
    direct BTF field store rejected with "only read is supported";
    global-subprogram candidate loaded, attached, and runtime-confirmed.

  With this series applied:
    direct BTF field store rejected with "only read is supported";
    global-subprogram candidate rejected with "only read is supported".

Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
---
====================

Link: https://patch.msgid.link/20260609-f01-04-btf-writable-arg-v1-0-f449cd970669@mails.tsinghua.edu.cn
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
Kumar Kartikeya Dwivedi 2026-06-09 17:39:46 +02:00
commit f1a660bbd1
No known key found for this signature in database
GPG Key ID: 472D377B63542F83
2 changed files with 20 additions and 1 deletions

View File

@ -6777,7 +6777,7 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, struct bpf_reg_
zero_size_allowed, access_type, meta);
case PTR_TO_BTF_ID:
return check_ptr_to_btf_access(env, regs, reg, argno, 0,
access_size, BPF_READ, -1);
access_size, access_type, -1);
case PTR_TO_CTX:
/* Only permit reading or writing syscall context using helper calls. */
if (is_var_ctx_off_allowed(env->prog)) {

View File

@ -287,6 +287,25 @@ int trusted_to_untrusted_mem(void *ctx)
return subprog_void_untrusted(bpf_get_current_task_btf());
}
__weak int subprog_write_mem_arg(int *p)
{
if (!p)
return 0;
*p = 42;
return 0;
}
SEC("?tp_btf/task_newtask")
__failure
__msg("only read is supported")
int trusted_btf_field_to_writable_mem(void *ctx)
{
struct task_struct *task = bpf_get_current_task_btf();
return subprog_write_mem_arg(&task->prio);
}
SEC("tp_btf/sys_enter")
__success
int anything_to_untrusted_mem(void *ctx)