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