diff options
| author | Alexei Starovoitov <ast@kernel.org> | 2026-11-01 19:05:19 +0000 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2026-11-02 00:10:39 +0000 |
| commit | faea3cda41d3deb4f28e7970c556896b1aa8bd76 (patch) | |
| tree | a16c321eb9ac44a85b4c5280cbcd558e6cf3a393 /include | |
| parent | ed02b9cc1d377d03da2507c3a858f0874aef7494 (diff) | |
bpf: Compare the arguments of an extension with those of its target
An extension replaces its target, a global function of another prog. From
BTF, btf_prepare_func_args() derives the kind of each argument, such as the
context, memory of a given size or a kernel object. The verifier checks the
callers with the BTF of the target and the extension with its own BTF.
Only btf_check_func_type_match() compares the two prototypes. For a pointer
to a struct, it compares only the struct names and assumes that the pointer
is the context. That was true until the commit below added pointers to
memory. Later the __arg_* tags added more kinds. Thus an extension can rely
on more than the callers guarantee (size, not NULL, kind). Then what the
verifier proved for it is false at run time.
Keep the result of btf_prepare_func_args() in bpf_func_info_aux and compare
the two results at load and on attach to another target. Return -EINVAL
unless the kind and the BTF id are the same and the memory is not larger.
The extension can also accept NULL where the callers never pass it. An
extension with the prototype and the tags of its target loads as before. An
argument that is the context only because of __arg_ctx needs the tag in the
extension too. The tag __arg_untrusted or __arg_arena on the extension only
is safe, but it is rejected because the kind differs.
Fixes: e5069b9c23b3 ("bpf: Support pointers in global func args")
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261101190535.1454146-12-alexei.starovoitov@gmail.com
Diffstat (limited to 'include')
| -rw-r--r-- | include/linux/bpf.h | 10 | ||||
| -rw-r--r-- | include/linux/bpf_verifier.h | 8 |
2 files changed, 10 insertions, 8 deletions
diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 1a8c3e514284..0b44bcb4f56e 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1752,12 +1752,22 @@ enum bpf_func_context { BPF_FUNC_CTX_CNT, }; +struct bpf_subprog_arg_info { + enum bpf_arg_type arg_type; + union { + u32 mem_size; + u32 btf_id; + }; +}; + struct bpf_func_info_aux { u16 linkage; bool unreliable; bool called[BPF_FUNC_CTX_CNT]; bool verified[BPF_FUNC_CTX_CNT]; bool called_with_pkt_ptrs; + /* what the callers of a global function are checked against */ + struct bpf_subprog_arg_info args[MAX_BPF_FUNC_REG_ARGS]; }; enum bpf_jit_poke_reason { diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 8852c173c53e..33dc3d402057 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -923,14 +923,6 @@ struct bpf_func_ptr { /* the subprog that a bpf_func_ptr pointed to was removed as dead code */ #define BPF_FUNC_PTR_DELETED ((u32)-1) -struct bpf_subprog_arg_info { - enum bpf_arg_type arg_type; - union { - u32 mem_size; - u32 btf_id; - }; -}; - enum priv_stack_mode { PRIV_STACK_UNKNOWN, NO_PRIV_STACK, |
