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 <[email protected]>
---
 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


Reply via email to