u64 value;
                bool found;
        } arg_constant;
+       struct {
+               struct btf *btf;
+               u32 btf_id;
+       } arg_obj_drop;
 };
 
 static bool is_kfunc_acquire(struct bpf_kfunc_call_arg_meta *meta)
        return __kfunc_param_match_suffix(btf, arg, "__ign");
 }
 
+static bool is_kfunc_arg_alloc_obj(const struct btf *btf, const struct btf_param *arg)
+{
+       return __kfunc_param_match_suffix(btf, arg, "__alloc");
+}
+
 static bool is_kfunc_arg_scalar_with_name(const struct btf *btf,
                                          const struct btf_param *arg,
                                          const char *name)
 
 enum kfunc_ptr_arg_type {
        KF_ARG_PTR_TO_CTX,
+       KF_ARG_PTR_TO_ALLOC_BTF_ID,  /* Allocated object */
        KF_ARG_PTR_TO_KPTR,          /* PTR_TO_KPTR but type specific */
        KF_ARG_PTR_TO_DYNPTR,
        KF_ARG_PTR_TO_BTF_ID,        /* Also covers reg2btf_ids conversions */
        KF_ARG_PTR_TO_MEM_SIZE,      /* Size derived from next argument, skip it */
 };
 
+enum special_kfunc_type {
+       KF_bpf_obj_new_impl,
+       KF_bpf_obj_drop_impl,
+};
+
+BTF_SET_START(special_kfunc_set)
+BTF_ID(func, bpf_obj_new_impl)
+BTF_ID(func, bpf_obj_drop_impl)
+BTF_SET_END(special_kfunc_set)
+
+BTF_ID_LIST(special_kfunc_list)
+BTF_ID(func, bpf_obj_new_impl)
+BTF_ID(func, bpf_obj_drop_impl)
+
 static enum kfunc_ptr_arg_type
 get_kfunc_ptr_arg_type(struct bpf_verifier_env *env,
                       struct bpf_kfunc_call_arg_meta *meta,
        if (btf_get_prog_ctx_type(&env->log, meta->btf, t, resolve_prog_type(env->prog), argno))
                return KF_ARG_PTR_TO_CTX;
 
+       if (is_kfunc_arg_alloc_obj(meta->btf, &args[argno]))
+               return KF_ARG_PTR_TO_ALLOC_BTF_ID;
+
        if (is_kfunc_arg_kptr_get(meta, argno)) {
                if (!btf_type_is_ptr(ref_t)) {
                        verbose(env, "arg#0 BTF type must be a double pointer for kptr_get kfunc\n");
                        return kf_arg_type;
 
                switch (kf_arg_type) {
+               case KF_ARG_PTR_TO_ALLOC_BTF_ID:
                case KF_ARG_PTR_TO_BTF_ID:
                        if (!is_kfunc_trusted_args(meta))
                                break;
                                return -EINVAL;
                        }
                        break;
+               case KF_ARG_PTR_TO_ALLOC_BTF_ID:
+                       if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
+                               verbose(env, "arg#%d expected pointer to allocated object\n", i);
+                               return -EINVAL;
+                       }
+                       if (!reg->ref_obj_id) {
+                               verbose(env, "allocated object must be referenced\n");
+                               return -EINVAL;
+                       }
+                       if (meta->btf == btf_vmlinux &&
+                           meta->func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) {
+                               meta->arg_obj_drop.btf = reg->btf;
+                               meta->arg_obj_drop.btf_id = reg->btf_id;
+                       }
+                       break;
                case KF_ARG_PTR_TO_KPTR:
                        if (reg->type != PTR_TO_MAP_VALUE) {
                                verbose(env, "arg#0 expected pointer to map value\n");
        return 0;
 }
 
-enum special_kfunc_type {
-       KF_bpf_obj_new_impl,
-};
-
-BTF_SET_START(special_kfunc_set)
-BTF_ID(func, bpf_obj_new_impl)
-BTF_SET_END(special_kfunc_set)
-
-BTF_ID_LIST(special_kfunc_list)
-BTF_ID(func, bpf_obj_new_impl)
-
 static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
                            int *insn_idx_p)
 {
                                env->insn_aux_data[insn_idx].obj_new_size = ret_t->size;
                                env->insn_aux_data[insn_idx].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]) {
+                               env->insn_aux_data[insn_idx].kptr_struct_meta =
+                                       btf_find_struct_meta(meta.arg_obj_drop.btf,
+                                                            meta.arg_obj_drop.btf_id);
                        } else {
                                verbose(env, "kernel function %s unhandled dynamic return type\n",
                                        meta.func_name);
                insn_buf[2] = addr[1];
                insn_buf[3] = *insn;
                *cnt = 4;
+       } else if (desc->func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) {
+               struct btf_struct_meta *kptr_struct_meta = env->insn_aux_data[insn_idx].kptr_struct_meta;
+               struct bpf_insn addr[2] = { BPF_LD_IMM64(BPF_REG_2, (long)kptr_struct_meta) };
+
+               insn_buf[0] = addr[0];
+               insn_buf[1] = addr[1];
+               insn_buf[2] = *insn;
+               *cnt = 3;
        }
        return 0;
 }