bpf_obj_new() and bpf_percpu_obj_new() allocate the static BTF size for the selected program-BTF type. A struct type can still end with a zero-length flexible array, and generic BTF struct walks have special handling that can accept accesses beyond the static struct size through such a member. Reject allocation kfunc types with trailing flexible arrays before marking the return value as PTR_TO_BTF_ID | MEM_ALLOC. This keeps the verifier-visible BTF access shape aligned with the object size allocated by the runtime kfunc. Fixes: 958cf2e273f0 ("bpf: Introduce bpf_obj_new") Fixes: 36d8bdf75a93 ("bpf: Add alloc/xchg/direct_access support for local percpu kptr") Signed-off-by: Yiyang Chen --- kernel/bpf/verifier.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 2abc79dbf..c3a574cc0 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10955,6 +10955,30 @@ static bool __btf_type_is_scalar_struct(struct bpf_verifier_env *env, return true; } +static bool btf_type_has_trailing_flex_array(const struct btf *btf, + const struct btf_type *t) +{ + const struct btf_type *member_type; + const struct btf_member *member; + const struct btf_array *array; + u32 vlen; + + if (!btf_type_is_struct(t)) + return false; + + vlen = btf_type_vlen(t); + if (!vlen) + return false; + + member = btf_type_member(t) + vlen - 1; + member_type = btf_type_skip_modifiers(btf, member->type, NULL); + if (!btf_type_is_array(member_type)) + return false; + + array = btf_array(member_type); + return !array->nelems; +} + enum kfunc_ptr_arg_type { KF_ARG_PTR_TO_CTX, KF_ARG_PTR_TO_ALLOC_BTF_ID, /* Allocated object */ @@ -12749,6 +12773,10 @@ static int check_special_kfunc(struct bpf_verifier_env *env, struct bpf_kfunc_ca verbose(env, "bpf_obj_new/bpf_percpu_obj_new type ID argument must be of a struct\n"); return -EINVAL; } + if (btf_type_has_trailing_flex_array(ret_btf, ret_t)) { + verbose(env, "bpf_obj_new type must not contain a flexible array\n"); + return -EINVAL; + } if (is_bpf_percpu_obj_new_kfunc(meta->func_id)) { if (ret_t->size > BPF_GLOBAL_PERCPU_MA_MAX_SIZE) { -- 2.34.1