> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index add3affc57035..8bdcb65618d01 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -5682,6 +5682,10 @@ BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct dentry) {
> struct inode *d_inode;
> };
>
> +BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct linux_binprm) {
> + struct mm_struct *mm;
> +};
> +
Does this break the BPF load-compatibility guarantee documented in
Documentation/bpf/bpf_design_QA.rst?
Before this patch, walking bprm->mm produced a dereferenceable register
in every program type. In sleepable programs, in_rcu_cs() is false, so
check_ptr_to_btf_access() sets flag = PTR_UNTRUSTED. In non-sleepable
programs, in_rcu_cs() is true but mm is not in any __safe_rcu* list, so
clear_trusted_flags() produces a plain PTR_TO_BTF_ID.
Both PTR_TO_BTF_ID and PTR_TO_BTF_ID|PTR_UNTRUSTED satisfy the guard in
check_mem_access():
} else if (base_type(reg->type) == PTR_TO_BTF_ID &&
!type_may_be_null(reg->type)) {
err = check_ptr_to_btf_access(env, regs, reg, argno, off, size, t,
value_regno);
so bprm->mm->arg_start loads with no NULL check.
After this patch, btf_nested_type_is_trusted() matches
linux_binprm__safe_trusted_or_null.mm, so check_ptr_to_btf_access() sets
flag |= PTR_TRUSTED | PTR_MAYBE_NULL. Now type_may_be_null() is true, the
arm above is skipped, and control falls to the final else:
} else {
verbose(env, "%s invalid mem access '%s'\n", reg_arg_name(env, argno),
reg_type_str(env, reg->type));
return -EACCES;
}
Any existing program that reads through bprm->mm without an explicit NULL
check now fails bpf_prog_load() with -EACCES.
> @@ -5732,6 +5736,7 @@ static bool type_is_trusted_or_null(struct bpf_verifier_env *env,
> {
> BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct socket));
> BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct dentry));
> + BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct linux_binprm));
> BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED_OR_NULL(struct vm_area_struct));
>
> return btf_nested_type_is_trusted(&env->log, reg, field_name, btf_id,
> diff --git a/tools/testing/selftests/bpf/progs/lsm.c b/tools/testing/selftests/bpf/progs/lsm.c
> index 7de173daf27b6..7441d66c080c9 100644
> --- a/tools/testing/selftests/bpf/progs/lsm.c
> +++ b/tools/testing/selftests/bpf/progs/lsm.c
> @@ -113,6 +113,7 @@ int BPF_PROG(test_void_hook, struct linux_binprm *bprm)
> {
> __u32 pid = bpf_get_current_pid_tgid() >> 32;
> struct inner_map *inner_map;
> + struct mm_struct *mm;
> char args[64];
> __u32 key = 0;
> __u64 *value;
> @@ -121,7 +122,9 @@ int BPF_PROG(test_void_hook, struct linux_binprm *bprm)
> bprm_count++;
>
> bpf_copy_from_user(args, sizeof(args), (void *)bprm->vma->vm_mm->arg_start);
> - bpf_copy_from_user(args, sizeof(args), (void *)bprm->mm->arg_start);
> + mm = bprm->mm;
> + if (mm)
> + bpf_copy_from_user(args, sizeof(args), (void *)mm->arg_start);
>
> value = bpf_map_lookup_elem(&array, &key);
> if (value)
The selftest rewrite above shows the problem: the old form
bpf_copy_from_user(args, sizeof(args), (void *)bprm->mm->arg_start) now
requires a NULL check. Out-of-tree BPF LSM and tracing programs that read
bprm->mm the same way will stop loading on kernel upgrade with no source
change on their side.
The bpf_design_QA.rst compatibility guarantee states: "The bpf development
process guarantees that the future kernel versions will accept all bpf
programs that were accepted by the earlier versions."
The tracing-program exception in that document does not cover this case:
struct linux_binprm's layout is unchanged, the program source is unchanged,
and the in-tree casualty is a BPF LSM program, not a bpf_probe_read()-based
tracing program.
Should the changelog mention the compatibility impact and document that
programs dereferencing bprm->mm now need a NULL check?
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31488001112
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.