Skip to content

Commit 83b8a67

Browse files
liu-song-6Kernel Patches Daemon
authored andcommitted
bpf: Extend btf_kfunc_id_set to handle kfunc polymorphism
Polymorphism exists in kernel functions, BPF helpers, as well as kfuncs. When called from different contexts, it is necessary to pick the right version of a kfunc. One of such example is bpf_dynptr_from_skb vs. bpf_dynptr_from_skb_rdonly. To avoid the burden on the users, the verifier can inspect the calling context and select the right version of kfunc. However, with more kfuncs being added to the kernel, it is not scalable to push all these logic to the verifiler. Extend btf_kfunc_id_set to handle kfunc polymorphism. Specifically, a list of kfuncs, "hidden_set", and a new method "remap" is added to btf_kfunc_id_set. kfuncs in hidden_set do not have BTF_SET8_KFUNCS flag, and are not exposed in vmlinux.h. The remap method is used to inspect the calling context, and when necessary, remap the user visible kfuncs (for example, bpf_dynptr_from_skb), to its hidden version (for example, bpf_dynptr_from_skb_rdonly). The verifier calls in these remap logic via the new btf_kfunc_id_remap() API, and picks the right kfuncs for the context. Signed-off-by: Song Liu <song@kernel.org>
1 parent a174051 commit 83b8a67

File tree

4 files changed

+128
-19
lines changed

4 files changed

+128
-19
lines changed

include/linux/btf.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,23 @@ struct btf_id_set;
114114
struct bpf_prog;
115115

116116
typedef int (*btf_kfunc_filter_t)(const struct bpf_prog *prog, u32 kfunc_id);
117+
typedef u32 (*btf_kfunc_remap_t)(const struct bpf_prog *prog, u32 kfunc_id);
117118

118119
struct btf_kfunc_id_set {
119120
struct module *owner;
120121
struct btf_id_set8 *set;
122+
123+
/* *hidden_set* contains kfuncs that are not exposed as kfunc in
124+
* vmlinux.h. These kfuncs are usually a variation of a kfunc
125+
* in *set*.
126+
*/
127+
struct btf_id_set8 *hidden_set;
121128
btf_kfunc_filter_t filter;
129+
130+
/* *remap* method remaps kfuncs in *set* to proper version in
131+
* *hidden_set*.
132+
*/
133+
btf_kfunc_remap_t remap;
122134
};
123135

124136
struct btf_id_dtor_kfunc {
@@ -575,6 +587,8 @@ u32 *btf_kfunc_is_modify_return(const struct btf *btf, u32 kfunc_btf_id,
575587
int register_btf_kfunc_id_set(enum bpf_prog_type prog_type,
576588
const struct btf_kfunc_id_set *s);
577589
int register_btf_fmodret_id_set(const struct btf_kfunc_id_set *kset);
590+
u32 btf_kfunc_id_remap(const struct btf *btf, u32 kfunc_btf_id,
591+
const struct bpf_prog *prog);
578592
s32 btf_find_dtor_kfunc(struct btf *btf, u32 btf_id);
579593
int register_btf_id_dtor_kfuncs(const struct btf_id_dtor_kfunc *dtors, u32 add_cnt,
580594
struct module *owner);
@@ -637,6 +651,12 @@ static inline u32 *btf_kfunc_id_set_contains(const struct btf *btf,
637651
{
638652
return NULL;
639653
}
654+
static inline u32 btf_kfunc_id_remap(const struct btf *btf, u32 kfunc_btf_id,
655+
const struct bpf_prog *prog)
656+
{
657+
return kfunc_btf_id;
658+
}
659+
640660
static inline int register_btf_kfunc_id_set(enum bpf_prog_type prog_type,
641661
const struct btf_kfunc_id_set *s)
642662
{

include/linux/btf_ids.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,9 @@ extern struct btf_id_set8 name;
212212
#define BTF_KFUNCS_START(name) \
213213
__BTF_SET8_START(name, local, BTF_SET8_KFUNCS)
214214

215+
#define BTF_HIDDEN_KFUNCS_START(name) \
216+
__BTF_SET8_START(name, local, 0)
217+
215218
#define BTF_KFUNCS_END(name) \
216219
BTF_SET8_END(name)
217220

@@ -230,6 +233,7 @@ BTF_SET8_END(name)
230233
#define BTF_SET8_START(name) static struct btf_id_set8 __maybe_unused name = { 0 };
231234
#define BTF_SET8_END(name)
232235
#define BTF_KFUNCS_START(name) static struct btf_id_set8 __maybe_unused name = { .flags = BTF_SET8_KFUNCS };
236+
#define BTF_HIDDEN_KFUNCS_START(name) static struct btf_id_set8 __maybe_unused name = { .flags = BTF_SET8_KFUNCS };
233237
#define BTF_KFUNCS_END(name)
234238

235239
#endif /* CONFIG_DEBUG_INFO_BTF */

kernel/bpf/btf.c

Lines changed: 100 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -226,16 +226,23 @@ enum {
226226
BTF_KFUNC_SET_MAX_CNT = 256,
227227
BTF_DTOR_KFUNC_MAX_CNT = 256,
228228
BTF_KFUNC_FILTER_MAX_CNT = 16,
229+
BTF_KFUNC_REMAP_MAX_CNT = 16,
229230
};
230231

231232
struct btf_kfunc_hook_filter {
232233
btf_kfunc_filter_t filters[BTF_KFUNC_FILTER_MAX_CNT];
233234
u32 nr_filters;
234235
};
235236

237+
struct btf_kfunc_hook_remap {
238+
btf_kfunc_remap_t remaps[BTF_KFUNC_REMAP_MAX_CNT];
239+
u32 nr_remaps;
240+
};
241+
236242
struct btf_kfunc_set_tab {
237243
struct btf_id_set8 *sets[BTF_KFUNC_HOOK_MAX];
238244
struct btf_kfunc_hook_filter hook_filters[BTF_KFUNC_HOOK_MAX];
245+
struct btf_kfunc_hook_remap hook_remaps[BTF_KFUNC_HOOK_MAX];
239246
};
240247

241248
struct btf_id_dtor_kfunc_tab {
@@ -8372,31 +8379,52 @@ static int btf_check_kfunc_protos(struct btf *btf, u32 func_id, u32 func_flags)
83728379

83738380
/* Kernel Function (kfunc) BTF ID set registration API */
83748381

8382+
static void btf_add_kfunc_to_set(struct btf *btf, struct btf_id_set8 *set,
8383+
struct btf_id_set8 *add_set)
8384+
{
8385+
u32 i;
8386+
8387+
if (!add_set)
8388+
return;
8389+
/* Concatenate the two sets */
8390+
memcpy(set->pairs + set->cnt, add_set->pairs, add_set->cnt * sizeof(set->pairs[0]));
8391+
/* Now that the set is copied, update with relocated BTF ids */
8392+
for (i = set->cnt; i < set->cnt + add_set->cnt; i++)
8393+
set->pairs[i].id = btf_relocate_id(btf, set->pairs[i].id);
8394+
8395+
set->cnt += add_set->cnt;
8396+
8397+
sort(set->pairs, set->cnt, sizeof(set->pairs[0]), btf_id_cmp_func, NULL);
8398+
}
8399+
83758400
static int btf_populate_kfunc_set(struct btf *btf, enum btf_kfunc_hook hook,
83768401
const struct btf_kfunc_id_set *kset)
83778402
{
83788403
struct btf_kfunc_hook_filter *hook_filter;
8379-
struct btf_id_set8 *add_set = kset->set;
8404+
struct btf_kfunc_hook_remap *hook_remap;
83808405
bool vmlinux_set = !btf_is_module(btf);
83818406
bool add_filter = !!kset->filter;
8407+
bool add_remap = !!kset->remap;
83828408
struct btf_kfunc_set_tab *tab;
83838409
struct btf_id_set8 *set;
8384-
u32 set_cnt, i;
8410+
u32 set_cnt, add_cnt, i;
83858411
int ret;
83868412

83878413
if (hook >= BTF_KFUNC_HOOK_MAX) {
83888414
ret = -EINVAL;
83898415
goto end;
83908416
}
83918417

8392-
if (!add_set->cnt)
8418+
add_cnt = kset->set->cnt;
8419+
if (kset->hidden_set)
8420+
add_cnt += kset->hidden_set->cnt;
8421+
8422+
if (!add_cnt)
83938423
return 0;
83948424

83958425
tab = btf->kfunc_set_tab;
83968426

83978427
if (tab && add_filter) {
8398-
u32 i;
8399-
84008428
hook_filter = &tab->hook_filters[hook];
84018429
for (i = 0; i < hook_filter->nr_filters; i++) {
84028430
if (hook_filter->filters[i] == kset->filter) {
@@ -8411,6 +8439,21 @@ static int btf_populate_kfunc_set(struct btf *btf, enum btf_kfunc_hook hook,
84118439
}
84128440
}
84138441

8442+
if (tab && add_remap) {
8443+
hook_remap = &tab->hook_remaps[hook];
8444+
for (i = 0; i < hook_remap->nr_remaps; i++) {
8445+
if (hook_remap->remaps[i] == kset->remap) {
8446+
add_remap = false;
8447+
break;
8448+
}
8449+
}
8450+
8451+
if (add_remap && hook_remap->nr_remaps == BTF_KFUNC_REMAP_MAX_CNT) {
8452+
ret = -E2BIG;
8453+
goto end;
8454+
}
8455+
}
8456+
84148457
if (!tab) {
84158458
tab = kzalloc(sizeof(*tab), GFP_KERNEL | __GFP_NOWARN);
84168459
if (!tab)
@@ -8439,19 +8482,19 @@ static int btf_populate_kfunc_set(struct btf *btf, enum btf_kfunc_hook hook,
84398482
*/
84408483
set_cnt = set ? set->cnt : 0;
84418484

8442-
if (set_cnt > U32_MAX - add_set->cnt) {
8485+
if (set_cnt > U32_MAX - add_cnt) {
84438486
ret = -EOVERFLOW;
84448487
goto end;
84458488
}
84468489

8447-
if (set_cnt + add_set->cnt > BTF_KFUNC_SET_MAX_CNT) {
8490+
if (set_cnt + add_cnt > BTF_KFUNC_SET_MAX_CNT) {
84488491
ret = -E2BIG;
84498492
goto end;
84508493
}
84518494

84528495
/* Grow set */
84538496
set = krealloc(tab->sets[hook],
8454-
offsetof(struct btf_id_set8, pairs[set_cnt + add_set->cnt]),
8497+
offsetof(struct btf_id_set8, pairs[set_cnt + add_cnt]),
84558498
GFP_KERNEL | __GFP_NOWARN);
84568499
if (!set) {
84578500
ret = -ENOMEM;
@@ -8463,20 +8506,18 @@ static int btf_populate_kfunc_set(struct btf *btf, enum btf_kfunc_hook hook,
84638506
set->cnt = 0;
84648507
tab->sets[hook] = set;
84658508

8466-
/* Concatenate the two sets */
8467-
memcpy(set->pairs + set->cnt, add_set->pairs, add_set->cnt * sizeof(set->pairs[0]));
8468-
/* Now that the set is copied, update with relocated BTF ids */
8469-
for (i = set->cnt; i < set->cnt + add_set->cnt; i++)
8470-
set->pairs[i].id = btf_relocate_id(btf, set->pairs[i].id);
8471-
8472-
set->cnt += add_set->cnt;
8473-
8474-
sort(set->pairs, set->cnt, sizeof(set->pairs[0]), btf_id_cmp_func, NULL);
8509+
btf_add_kfunc_to_set(btf, set, kset->set);
8510+
btf_add_kfunc_to_set(btf, set, kset->hidden_set);
84758511

84768512
if (add_filter) {
84778513
hook_filter = &tab->hook_filters[hook];
84788514
hook_filter->filters[hook_filter->nr_filters++] = kset->filter;
84798515
}
8516+
8517+
if (add_remap) {
8518+
hook_remap = &tab->hook_remaps[hook];
8519+
hook_remap->remaps[hook_remap->nr_remaps++] = kset->remap;
8520+
}
84808521
return 0;
84818522
end:
84828523
btf_free_kfunc_set_tab(btf);
@@ -8511,6 +8552,28 @@ static u32 *__btf_kfunc_id_set_contains(const struct btf *btf,
85118552
return id + 1;
85128553
}
85138554

8555+
static u32 __btf_kfunc_id_remap(const struct btf *btf,
8556+
enum btf_kfunc_hook hook,
8557+
u32 kfunc_btf_id,
8558+
const struct bpf_prog *prog)
8559+
{
8560+
struct btf_kfunc_hook_remap *hook_remap;
8561+
u32 i, remap_id = 0;
8562+
8563+
if (hook >= BTF_KFUNC_HOOK_MAX)
8564+
return 0;
8565+
if (!btf->kfunc_set_tab)
8566+
return 0;
8567+
hook_remap = &btf->kfunc_set_tab->hook_remaps[hook];
8568+
8569+
for (i = 0; i < hook_remap->nr_remaps; i++) {
8570+
remap_id = hook_remap->remaps[i](prog, kfunc_btf_id);
8571+
if (remap_id)
8572+
break;
8573+
}
8574+
return remap_id;
8575+
}
8576+
85148577
static int bpf_prog_type_to_kfunc_hook(enum bpf_prog_type prog_type)
85158578
{
85168579
switch (prog_type) {
@@ -8579,6 +8642,26 @@ u32 *btf_kfunc_id_set_contains(const struct btf *btf,
85798642
return __btf_kfunc_id_set_contains(btf, hook, kfunc_btf_id, prog);
85808643
}
85818644

8645+
/* Reference to the module (obtained using btf_try_get_module)
8646+
* corresponding to the struct btf *MUST* be held when calling this
8647+
* function from the verifier
8648+
*/
8649+
u32 btf_kfunc_id_remap(const struct btf *btf, u32 kfunc_btf_id,
8650+
const struct bpf_prog *prog)
8651+
{
8652+
enum bpf_prog_type prog_type = resolve_prog_type(prog);
8653+
enum btf_kfunc_hook hook;
8654+
u32 remap_id;
8655+
8656+
remap_id = __btf_kfunc_id_remap(btf, BTF_KFUNC_HOOK_COMMON, kfunc_btf_id, prog);
8657+
if (remap_id)
8658+
return remap_id;
8659+
8660+
hook = bpf_prog_type_to_kfunc_hook(prog_type);
8661+
remap_id = __btf_kfunc_id_remap(btf, hook, kfunc_btf_id, prog);
8662+
return remap_id ?: kfunc_btf_id;
8663+
}
8664+
85828665
u32 *btf_kfunc_is_modify_return(const struct btf *btf, u32 kfunc_btf_id,
85838666
const struct bpf_prog *prog)
85848667
{

kernel/bpf/verifier.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3029,13 +3029,14 @@ static struct btf *find_kfunc_desc_btf(struct bpf_verifier_env *env, s16 offset)
30293029
return btf_vmlinux ?: ERR_PTR(-ENOENT);
30303030
}
30313031

3032-
static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
3032+
static int add_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, s16 offset)
30333033
{
30343034
const struct btf_type *func, *func_proto;
30353035
struct bpf_kfunc_btf_tab *btf_tab;
30363036
struct bpf_kfunc_desc_tab *tab;
30373037
struct bpf_prog_aux *prog_aux;
30383038
struct bpf_kfunc_desc *desc;
3039+
u32 func_id = insn->imm;
30393040
const char *func_name;
30403041
struct btf *desc_btf;
30413042
unsigned long call_imm;
@@ -3094,6 +3095,7 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
30943095
return PTR_ERR(desc_btf);
30953096
}
30963097

3098+
func_id = insn->imm = btf_kfunc_id_remap(desc_btf, insn->imm, env->prog);
30973099
if (find_kfunc_desc(env->prog, func_id, offset))
30983100
return 0;
30993101

@@ -3227,7 +3229,7 @@ static int add_subprog_and_kfunc(struct bpf_verifier_env *env)
32273229
if (bpf_pseudo_func(insn) || bpf_pseudo_call(insn))
32283230
ret = add_subprog(env, i + insn->imm + 1);
32293231
else
3230-
ret = add_kfunc_call(env, insn->imm, insn->off);
3232+
ret = add_kfunc_call(env, insn, insn->off);
32313233

32323234
if (ret < 0)
32333235
return ret;

0 commit comments

Comments
 (0)