Skip to content

Commit ac9f060

Browse files
kkdwvdAlexei Starovoitov
authored andcommitted
bpf: Introduce bpf_obj_drop
Introduce bpf_obj_drop, which is the kfunc used to free allocated objects (allocated using bpf_obj_new). Pairing with bpf_obj_new, it implicitly destructs the fields part of object automatically without user intervention. Just like the previous patch, btf_struct_meta that is needed to free up the special fields is passed as a hidden argument to the kfunc. For the user, a convenience macro hides over the kernel side kfunc which is named bpf_obj_drop_impl. Continuing the previous example: void prog(void) { struct foo *f; f = bpf_obj_new(typeof(*f)); if (!f) return; bpf_obj_drop(f); } Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20221118015614.2013203-15-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 958cf2e commit ac9f060

File tree

3 files changed

+79
-11
lines changed

3 files changed

+79
-11
lines changed

kernel/bpf/helpers.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,13 +1770,24 @@ void *bpf_obj_new_impl(u64 local_type_id__k, void *meta__ign)
17701770
return p;
17711771
}
17721772

1773+
void bpf_obj_drop_impl(void *p__alloc, void *meta__ign)
1774+
{
1775+
struct btf_struct_meta *meta = meta__ign;
1776+
void *p = p__alloc;
1777+
1778+
if (meta)
1779+
bpf_obj_free_fields(meta->record, p);
1780+
bpf_mem_free(&bpf_global_ma, p);
1781+
}
1782+
17731783
__diag_pop();
17741784

17751785
BTF_SET8_START(generic_btf_ids)
17761786
#ifdef CONFIG_KEXEC_CORE
17771787
BTF_ID_FLAGS(func, crash_kexec, KF_DESTRUCTIVE)
17781788
#endif
17791789
BTF_ID_FLAGS(func, bpf_obj_new_impl, KF_ACQUIRE | KF_RET_NULL)
1790+
BTF_ID_FLAGS(func, bpf_obj_drop_impl, KF_RELEASE)
17801791
BTF_SET8_END(generic_btf_ids)
17811792

17821793
static const struct btf_kfunc_id_set generic_kfunc_set = {

kernel/bpf/verifier.c

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7879,6 +7879,10 @@ struct bpf_kfunc_call_arg_meta {
78797879
u64 value;
78807880
bool found;
78817881
} arg_constant;
7882+
struct {
7883+
struct btf *btf;
7884+
u32 btf_id;
7885+
} arg_obj_drop;
78827886
};
78837887

78847888
static bool is_kfunc_acquire(struct bpf_kfunc_call_arg_meta *meta)
@@ -7957,6 +7961,11 @@ static bool is_kfunc_arg_ignore(const struct btf *btf, const struct btf_param *a
79577961
return __kfunc_param_match_suffix(btf, arg, "__ign");
79587962
}
79597963

7964+
static bool is_kfunc_arg_alloc_obj(const struct btf *btf, const struct btf_param *arg)
7965+
{
7966+
return __kfunc_param_match_suffix(btf, arg, "__alloc");
7967+
}
7968+
79607969
static bool is_kfunc_arg_scalar_with_name(const struct btf *btf,
79617970
const struct btf_param *arg,
79627971
const char *name)
@@ -8051,13 +8060,28 @@ static u32 *reg2btf_ids[__BPF_REG_TYPE_MAX] = {
80518060

80528061
enum kfunc_ptr_arg_type {
80538062
KF_ARG_PTR_TO_CTX,
8063+
KF_ARG_PTR_TO_ALLOC_BTF_ID, /* Allocated object */
80548064
KF_ARG_PTR_TO_KPTR, /* PTR_TO_KPTR but type specific */
80558065
KF_ARG_PTR_TO_DYNPTR,
80568066
KF_ARG_PTR_TO_BTF_ID, /* Also covers reg2btf_ids conversions */
80578067
KF_ARG_PTR_TO_MEM,
80588068
KF_ARG_PTR_TO_MEM_SIZE, /* Size derived from next argument, skip it */
80598069
};
80608070

8071+
enum special_kfunc_type {
8072+
KF_bpf_obj_new_impl,
8073+
KF_bpf_obj_drop_impl,
8074+
};
8075+
8076+
BTF_SET_START(special_kfunc_set)
8077+
BTF_ID(func, bpf_obj_new_impl)
8078+
BTF_ID(func, bpf_obj_drop_impl)
8079+
BTF_SET_END(special_kfunc_set)
8080+
8081+
BTF_ID_LIST(special_kfunc_list)
8082+
BTF_ID(func, bpf_obj_new_impl)
8083+
BTF_ID(func, bpf_obj_drop_impl)
8084+
80618085
static enum kfunc_ptr_arg_type
80628086
get_kfunc_ptr_arg_type(struct bpf_verifier_env *env,
80638087
struct bpf_kfunc_call_arg_meta *meta,
@@ -8078,6 +8102,9 @@ get_kfunc_ptr_arg_type(struct bpf_verifier_env *env,
80788102
if (btf_get_prog_ctx_type(&env->log, meta->btf, t, resolve_prog_type(env->prog), argno))
80798103
return KF_ARG_PTR_TO_CTX;
80808104

8105+
if (is_kfunc_arg_alloc_obj(meta->btf, &args[argno]))
8106+
return KF_ARG_PTR_TO_ALLOC_BTF_ID;
8107+
80818108
if (is_kfunc_arg_kptr_get(meta, argno)) {
80828109
if (!btf_type_is_ptr(ref_t)) {
80838110
verbose(env, "arg#0 BTF type must be a double pointer for kptr_get kfunc\n");
@@ -8294,6 +8321,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
82948321
return kf_arg_type;
82958322

82968323
switch (kf_arg_type) {
8324+
case KF_ARG_PTR_TO_ALLOC_BTF_ID:
82978325
case KF_ARG_PTR_TO_BTF_ID:
82988326
if (!is_kfunc_trusted_args(meta))
82998327
break;
@@ -8330,6 +8358,21 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
83308358
return -EINVAL;
83318359
}
83328360
break;
8361+
case KF_ARG_PTR_TO_ALLOC_BTF_ID:
8362+
if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
8363+
verbose(env, "arg#%d expected pointer to allocated object\n", i);
8364+
return -EINVAL;
8365+
}
8366+
if (!reg->ref_obj_id) {
8367+
verbose(env, "allocated object must be referenced\n");
8368+
return -EINVAL;
8369+
}
8370+
if (meta->btf == btf_vmlinux &&
8371+
meta->func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) {
8372+
meta->arg_obj_drop.btf = reg->btf;
8373+
meta->arg_obj_drop.btf_id = reg->btf_id;
8374+
}
8375+
break;
83338376
case KF_ARG_PTR_TO_KPTR:
83348377
if (reg->type != PTR_TO_MAP_VALUE) {
83358378
verbose(env, "arg#0 expected pointer to map value\n");
@@ -8400,17 +8443,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
84008443
return 0;
84018444
}
84028445

8403-
enum special_kfunc_type {
8404-
KF_bpf_obj_new_impl,
8405-
};
8406-
8407-
BTF_SET_START(special_kfunc_set)
8408-
BTF_ID(func, bpf_obj_new_impl)
8409-
BTF_SET_END(special_kfunc_set)
8410-
8411-
BTF_ID_LIST(special_kfunc_list)
8412-
BTF_ID(func, bpf_obj_new_impl)
8413-
84148446
static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
84158447
int *insn_idx_p)
84168448
{
@@ -8532,6 +8564,10 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
85328564
env->insn_aux_data[insn_idx].obj_new_size = ret_t->size;
85338565
env->insn_aux_data[insn_idx].kptr_struct_meta =
85348566
btf_find_struct_meta(ret_btf, ret_btf_id);
8567+
} else if (meta.func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) {
8568+
env->insn_aux_data[insn_idx].kptr_struct_meta =
8569+
btf_find_struct_meta(meta.arg_obj_drop.btf,
8570+
meta.arg_obj_drop.btf_id);
85358571
} else {
85368572
verbose(env, "kernel function %s unhandled dynamic return type\n",
85378573
meta.func_name);
@@ -14768,6 +14804,14 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
1476814804
insn_buf[2] = addr[1];
1476914805
insn_buf[3] = *insn;
1477014806
*cnt = 4;
14807+
} else if (desc->func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) {
14808+
struct btf_struct_meta *kptr_struct_meta = env->insn_aux_data[insn_idx].kptr_struct_meta;
14809+
struct bpf_insn addr[2] = { BPF_LD_IMM64(BPF_REG_2, (long)kptr_struct_meta) };
14810+
14811+
insn_buf[0] = addr[0];
14812+
insn_buf[1] = addr[1];
14813+
insn_buf[2] = *insn;
14814+
*cnt = 3;
1477114815
}
1477214816
return 0;
1477314817
}

tools/testing/selftests/bpf/bpf_experimental.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,17 @@ extern void *bpf_obj_new_impl(__u64 local_type_id, void *meta) __ksym;
2222
/* Convenience macro to wrap over bpf_obj_new_impl */
2323
#define bpf_obj_new(type) ((type *)bpf_obj_new_impl(bpf_core_type_id_local(type), NULL))
2424

25+
/* Description
26+
* Free an allocated object. All fields of the object that require
27+
* destruction will be destructed before the storage is freed.
28+
*
29+
* The 'meta' parameter is a hidden argument that is ignored.
30+
* Returns
31+
* Void.
32+
*/
33+
extern void bpf_obj_drop_impl(void *kptr, void *meta) __ksym;
34+
35+
/* Convenience macro to wrap over bpf_obj_drop_impl */
36+
#define bpf_obj_drop(kptr) bpf_obj_drop_impl(kptr, NULL)
37+
2538
#endif

0 commit comments

Comments
 (0)