Skip to content

Commit 5ce937d

Browse files
kkdwivediAlexei Starovoitov
authored andcommitted
bpf: Populate pairs of btf_id and destructor kfunc in btf
To support storing referenced PTR_TO_BTF_ID in maps, we require associating a specific BTF ID with a 'destructor' kfunc. This is because we need to release a live referenced pointer at a certain offset in map value from the map destruction path, otherwise we end up leaking resources. Hence, introduce support for passing an array of btf_id, kfunc_btf_id pairs that denote a BTF ID and its associated release function. Then, add an accessor 'btf_find_dtor_kfunc' which can be used to look up the destructor kfunc of a certain BTF ID. If found, we can use it to free the object from the map free path. The registration of these pairs also serve as a whitelist of structures which are allowed as referenced PTR_TO_BTF_ID in a BPF map, because without finding the destructor kfunc, we will bail and return an error. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20220424214901.2743946-7-memxor@gmail.com
1 parent 4d7d7f6 commit 5ce937d

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

include/linux/btf.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ struct btf_kfunc_id_set {
4040
};
4141
};
4242

43+
struct btf_id_dtor_kfunc {
44+
u32 btf_id;
45+
u32 kfunc_btf_id;
46+
};
47+
4348
extern const struct file_operations btf_fops;
4449

4550
void btf_get(struct btf *btf);
@@ -346,6 +351,9 @@ bool btf_kfunc_id_set_contains(const struct btf *btf,
346351
enum btf_kfunc_type type, u32 kfunc_btf_id);
347352
int register_btf_kfunc_id_set(enum bpf_prog_type prog_type,
348353
const struct btf_kfunc_id_set *s);
354+
s32 btf_find_dtor_kfunc(struct btf *btf, u32 btf_id);
355+
int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors, u32 add_cnt,
356+
struct module *owner);
349357
#else
350358
static inline const struct btf_type *btf_type_by_id(const struct btf *btf,
351359
u32 type_id)
@@ -369,6 +377,15 @@ static inline int register_btf_kfunc_id_set(enum bpf_prog_type prog_type,
369377
{
370378
return 0;
371379
}
380+
static inline s32 btf_find_dtor_kfunc(struct btf *btf, u32 btf_id)
381+
{
382+
return -ENOENT;
383+
}
384+
static inline int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors,
385+
u32 add_cnt, struct module *owner)
386+
{
387+
return 0;
388+
}
372389
#endif
373390

374391
#endif

kernel/bpf/btf.c

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,18 @@ enum btf_kfunc_hook {
207207

208208
enum {
209209
BTF_KFUNC_SET_MAX_CNT = 32,
210+
BTF_DTOR_KFUNC_MAX_CNT = 256,
210211
};
211212

212213
struct btf_kfunc_set_tab {
213214
struct btf_id_set *sets[BTF_KFUNC_HOOK_MAX][BTF_KFUNC_TYPE_MAX];
214215
};
215216

217+
struct btf_id_dtor_kfunc_tab {
218+
u32 cnt;
219+
struct btf_id_dtor_kfunc dtors[];
220+
};
221+
216222
struct btf {
217223
void *data;
218224
struct btf_type **types;
@@ -228,6 +234,7 @@ struct btf {
228234
u32 id;
229235
struct rcu_head rcu;
230236
struct btf_kfunc_set_tab *kfunc_set_tab;
237+
struct btf_id_dtor_kfunc_tab *dtor_kfunc_tab;
231238

232239
/* split BTF support */
233240
struct btf *base_btf;
@@ -1616,8 +1623,19 @@ static void btf_free_kfunc_set_tab(struct btf *btf)
16161623
btf->kfunc_set_tab = NULL;
16171624
}
16181625

1626+
static void btf_free_dtor_kfunc_tab(struct btf *btf)
1627+
{
1628+
struct btf_id_dtor_kfunc_tab *tab = btf->dtor_kfunc_tab;
1629+
1630+
if (!tab)
1631+
return;
1632+
kfree(tab);
1633+
btf->dtor_kfunc_tab = NULL;
1634+
}
1635+
16191636
static void btf_free(struct btf *btf)
16201637
{
1638+
btf_free_dtor_kfunc_tab(btf);
16211639
btf_free_kfunc_set_tab(btf);
16221640
kvfree(btf->types);
16231641
kvfree(btf->resolved_sizes);
@@ -7076,6 +7094,96 @@ int register_btf_kfunc_id_set(enum bpf_prog_type prog_type,
70767094
}
70777095
EXPORT_SYMBOL_GPL(register_btf_kfunc_id_set);
70787096

7097+
s32 btf_find_dtor_kfunc(struct btf *btf, u32 btf_id)
7098+
{
7099+
struct btf_id_dtor_kfunc_tab *tab = btf->dtor_kfunc_tab;
7100+
struct btf_id_dtor_kfunc *dtor;
7101+
7102+
if (!tab)
7103+
return -ENOENT;
7104+
/* Even though the size of tab->dtors[0] is > sizeof(u32), we only need
7105+
* to compare the first u32 with btf_id, so we can reuse btf_id_cmp_func.
7106+
*/
7107+
BUILD_BUG_ON(offsetof(struct btf_id_dtor_kfunc, btf_id) != 0);
7108+
dtor = bsearch(&btf_id, tab->dtors, tab->cnt, sizeof(tab->dtors[0]), btf_id_cmp_func);
7109+
if (!dtor)
7110+
return -ENOENT;
7111+
return dtor->kfunc_btf_id;
7112+
}
7113+
7114+
/* This function must be invoked only from initcalls/module init functions */
7115+
int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors, u32 add_cnt,
7116+
struct module *owner)
7117+
{
7118+
struct btf_id_dtor_kfunc_tab *tab;
7119+
struct btf *btf;
7120+
u32 tab_cnt;
7121+
int ret;
7122+
7123+
btf = btf_get_module_btf(owner);
7124+
if (!btf) {
7125+
if (!owner && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) {
7126+
pr_err("missing vmlinux BTF, cannot register dtor kfuncs\n");
7127+
return -ENOENT;
7128+
}
7129+
if (owner && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES)) {
7130+
pr_err("missing module BTF, cannot register dtor kfuncs\n");
7131+
return -ENOENT;
7132+
}
7133+
return 0;
7134+
}
7135+
if (IS_ERR(btf))
7136+
return PTR_ERR(btf);
7137+
7138+
if (add_cnt >= BTF_DTOR_KFUNC_MAX_CNT) {
7139+
pr_err("cannot register more than %d kfunc destructors\n", BTF_DTOR_KFUNC_MAX_CNT);
7140+
ret = -E2BIG;
7141+
goto end;
7142+
}
7143+
7144+
tab = btf->dtor_kfunc_tab;
7145+
/* Only one call allowed for modules */
7146+
if (WARN_ON_ONCE(tab && btf_is_module(btf))) {
7147+
ret = -EINVAL;
7148+
goto end;
7149+
}
7150+
7151+
tab_cnt = tab ? tab->cnt : 0;
7152+
if (tab_cnt > U32_MAX - add_cnt) {
7153+
ret = -EOVERFLOW;
7154+
goto end;
7155+
}
7156+
if (tab_cnt + add_cnt >= BTF_DTOR_KFUNC_MAX_CNT) {
7157+
pr_err("cannot register more than %d kfunc destructors\n", BTF_DTOR_KFUNC_MAX_CNT);
7158+
ret = -E2BIG;
7159+
goto end;
7160+
}
7161+
7162+
tab = krealloc(btf->dtor_kfunc_tab,
7163+
offsetof(struct btf_id_dtor_kfunc_tab, dtors[tab_cnt + add_cnt]),
7164+
GFP_KERNEL | __GFP_NOWARN);
7165+
if (!tab) {
7166+
ret = -ENOMEM;
7167+
goto end;
7168+
}
7169+
7170+
if (!btf->dtor_kfunc_tab)
7171+
tab->cnt = 0;
7172+
btf->dtor_kfunc_tab = tab;
7173+
7174+
memcpy(tab->dtors + tab->cnt, dtors, add_cnt * sizeof(tab->dtors[0]));
7175+
tab->cnt += add_cnt;
7176+
7177+
sort(tab->dtors, tab->cnt, sizeof(tab->dtors[0]), btf_id_cmp_func, NULL);
7178+
7179+
return 0;
7180+
end:
7181+
btf_free_dtor_kfunc_tab(btf);
7182+
btf_put(btf);
7183+
return ret;
7184+
}
7185+
EXPORT_SYMBOL_GPL(register_btf_id_dtor_kfuncs);
7186+
70797187
#define MAX_TYPES_ARE_COMPAT_DEPTH 2
70807188

70817189
static

0 commit comments

Comments
 (0)