]> git.itanic.dy.fi Git - linux-stable/commitdiff
bpf: Fix struct_meta lookup for bpf_obj_free_fields kfunc call
authorDave Marchevsky <davemarchevsky@fb.com>
Mon, 3 Apr 2023 20:00:27 +0000 (13:00 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 11 May 2023 14:17:15 +0000 (23:17 +0900)
[ Upstream commit f6a6a5a976288e4d0d94eb1c6c9e983e8e5cdb31 ]

bpf_obj_drop_impl has a void return type. In check_kfunc_call, the "else
if" which sets insn_aux->kptr_struct_meta for bpf_obj_drop_impl is
surrounded by a larger if statement which checks btf_type_is_ptr. As a
result:

  * The bpf_obj_drop_impl-specific code will never execute
  * The btf_struct_meta input to bpf_obj_drop is always NULL
  * __bpf_obj_drop_impl will always see a NULL btf_record when called
    from BPF program, and won't call bpf_obj_free_fields
  * program-allocated kptrs which have fields that should be cleaned up
    by bpf_obj_free_fields may instead leak resources

This patch adds a btf_type_is_void branch to the larger if and moves
special handling for bpf_obj_drop_impl there, fixing the issue.

Fixes: ac9f06050a35 ("bpf: Introduce bpf_obj_drop")
Cc: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>
Link: https://lore.kernel.org/r/20230403200027.2271029-1-davemarchevsky@fb.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
kernel/bpf/verifier.c

index 559c9137f834daa163aff788790961ccdf9cef72..64600acbb4e76e841ffb63ea1220ca15e77cdc3c 100644 (file)
@@ -10002,10 +10002,6 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
                                insn_aux->obj_new_size = ret_t->size;
                                insn_aux->kptr_struct_meta =
                                        btf_find_struct_meta(ret_btf, ret_btf_id);
-                       } else if (meta.func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) {
-                               insn_aux->kptr_struct_meta =
-                                       btf_find_struct_meta(meta.arg_obj_drop.btf,
-                                                            meta.arg_obj_drop.btf_id);
                        } else if (meta.func_id == special_kfunc_list[KF_bpf_list_pop_front] ||
                                   meta.func_id == special_kfunc_list[KF_bpf_list_pop_back]) {
                                struct btf_field *field = meta.arg_list_head.field;
@@ -10090,7 +10086,15 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 
                if (reg_may_point_to_spin_lock(&regs[BPF_REG_0]) && !regs[BPF_REG_0].id)
                        regs[BPF_REG_0].id = ++env->id_gen;
-       } /* else { add_kfunc_call() ensures it is btf_type_is_void(t) } */
+       } else if (btf_type_is_void(t)) {
+               if (meta.btf == btf_vmlinux && btf_id_set_contains(&special_kfunc_set, meta.func_id)) {
+                       if (meta.func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) {
+                               insn_aux->kptr_struct_meta =
+                                       btf_find_struct_meta(meta.arg_obj_drop.btf,
+                                                            meta.arg_obj_drop.btf_id);
+                       }
+               }
+       }
 
        nargs = btf_type_vlen(meta.func_proto);
        args = (const struct btf_param *)(meta.func_proto + 1);