Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider: - [High] bpf: crash on blind dereference of ERR_PTR from bpf_get_btf_vmlinux() - [High] bpf: single vmlinux BTF parse failure permanently bricks verifier - [Medium] bpf: context translation fails for EXT/TRACING progs without vmlinux BTF - [Medium] bpf: AB-BA deadlock between bpf_verifier_lock and request_module() - [Medium] bpf: bpf_snprintf_btf fails because vmlinux BTF load is skipped --
commit 68de9774165f5e9dfaacde093071f89754bece4b Author: Jay Wang <[email protected]> bpf: fetch the vmlinux BTF where kernel types enter a program This commit delays the fetching and parsing of vmlinux BTF in the BPF verifier, moving it from an upfront operation for all programs to an on-demand fetch. This prevents unnecessary module loading and memory usage for BPF programs that do not rely on kernel types. > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index a7c9e2d8965d5..2425ea74b61d6 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -2873,7 +2873,8 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, > u32 func_id, u16 offset) > tab = prog_aux->kfunc_tab; > btf_tab = prog_aux->kfunc_btf_tab; > if (!tab) { > - if (!btf_vmlinux) { > + /* with CONFIG_DEBUG_INFO_BTF=m this is where the vmlinux BTF > gets loaded */ > + if (IS_ERR_OR_NULL(bpf_get_btf_vmlinux())) { [Severity: Medium] Could this introduce an AB-BA deadlock with the module loader? For unprivileged programs, bpf_check() acquires bpf_verifier_lock before executing instruction verification. When CONFIG_DEBUG_INFO_BTF=m, this on-demand fetch calls request_module() which blocks and spawns a usermode helper (modprobe). If the usermode helper (or another user-space process triggered during the module load) attempts to load an unprivileged BPF program, it will block indefinitely waiting for bpf_verifier_lock. [ ... ] > @@ -11568,6 +11570,20 @@ static int release_reg(struct bpf_verifier_env *env, > struct bpf_reg_state *reg, > return err; > } > > +/* Does calling @fn bring kernel BTF types into the program state? */ > +static bool helper_uses_vmlinux_btf(const struct bpf_func_proto *fn) > +{ > + int i; > + > + if (base_type(fn->ret_type) == RET_PTR_TO_BTF_ID) > + return true; > + for (i = 0; i < MAX_BPF_FUNC_ARGS; i++) { > + if (base_type(fn->arg_type[i]) == ARG_PTR_TO_BTF_ID) > + return true; > + } > + return false; > +} [Severity: Medium] Does this logic miss helpers that require the vmlinux BTF but don't explicitly take or return a PTR_TO_BTF_ID? For instance, the bpf_snprintf_btf helper takes a struct btf_ptr * as an ARG_PTR_TO_MEM. Because this isn't caught by helper_uses_vmlinux_btf(), the verifier skips loading the BTF. At runtime, the helper calls bpf_peek_btf_vmlinux(). Since the module was never loaded by the verifier, this returns NULL and the helper functionally fails with -EINVAL, potentially breaking valid BPF programs that rely on it. [ ... ] > @@ -21724,7 +21762,11 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr > *attr, bpfptr_t uattr, > if (ret) > goto err_prep; > > - bpf_get_btf_vmlinux(); > + /* > + * The vmlinux BTF is not fetched up front: with CONFIG_DEBUG_INFO_BTF=m > + * it is loaded on demand, at the points where kernel types enter the > + * program (attach_btf, kfuncs, ksyms, map pointers, BTF-typed helpers). > + */ [Severity: High] Can a single transient module load or parse failure permanently brick the verifier? If bpf_get_btf_vmlinux() fails (e.g., due to ENOMEM or a temporary module load failure), btf_parse_vmlinux() returns an ERR_PTR which is permanently cached in btf_vmlinux via smp_store_release(&btf_vmlinux, btf). The verifier unconditionally checks if (IS_ERR(btf_vmlinux)) at the beginning of bpf_check(). Consequently, a single transient failure permanently breaks the loading of all subsequent BPF programs system-wide, including those that do not require BTF. [Severity: Medium] Does removing this upfront fetch break context translation for EXT and TRACING programs? When loading a BPF_PROG_TYPE_EXT or BPF_PROG_TYPE_TRACING program targeting another BPF program, bpf_prog_load() skips fetching the vmlinux BTF. If the program does not trigger an on-demand BTF load via kfuncs or helpers, the global bpf_ctx_convert.t remains NULL. During verification, btf_ctx_access() calls btf_translate_to_vmlinux(), which uses find_canonical_prog_ctx_type(). Because bpf_ctx_convert.t is NULL, translation fails and the verifier incorrectly rejects valid context accesses. [Severity: High] Does delaying the BTF load expose paths to blind ERR_PTR dereferences? Because the patch makes the BTF load lazy, it is more likely to fail much later in the verification process, exposing paths that blindly dereference the pointer returned by bpf_get_btf_vmlinux() without checking IS_ERR(). For example, btf_prepare_func_args() does: vmlinux_btf = bpf_get_btf_vmlinux(); ref_t = btf_type_by_id(vmlinux_btf, kern_type_id); And btf_check_kfunc_name() does: id = btf_find_by_name_kind(bpf_get_btf_vmlinux(), func_name, kind); If bpf_get_btf_vmlinux() returns an ERR_PTR, passing it directly to these functions will result in a kernel panic. -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=3
