Skip to content

Commit faadc69

Browse files
author
Alexei Starovoitov
committed
Merge branch 'add-kernel-symbol-for-struct_ops-trampoline'
Xu Kuohai says: ==================== Add kernel symbol for struct_ops trampoline. Without kernel symbol for struct_ops trampoline, the unwinder may produce unexpected stacktraces. For example, the x86 ORC and FP unwinder stops stacktrace on a struct_ops trampoline address since there is no kernel symbol for the address. v4: - Add a separate cleanup patch to remove unused member rcu from bpf_struct_ops_map (patch 1) - Use funcs_cnt instead of btf_type_vlen(vt) for links memory calculation in .map_mem_usage (patch 2) - Include ksyms[] memory in map_mem_usage (patch 3) - Various fixes in patch 3 (Thanks to Martin) v3: https://lore.kernel.org/bpf/[email protected]/ - Add a separate cleanup patch to replace links_cnt with funcs_cnt - Allocate ksyms on-demand in update_elem() to stay with the links allocation way - Set ksym name to prog__<struct_ops_name>_<member_name> v2: https://lore.kernel.org/bpf/[email protected]/ - Refine the commit message for clarity and fix a test bot warning v1: https://lore.kernel.org/bpf/[email protected]/ ==================== Reviewed-by: Martin KaFai Lau <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents c1bc51f + 7c8ce4f commit faadc69

File tree

4 files changed

+114
-16
lines changed

4 files changed

+114
-16
lines changed

include/linux/bpf.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1402,7 +1402,8 @@ int arch_prepare_bpf_dispatcher(void *image, void *buf, s64 *funcs, int num_func
14021402
void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from,
14031403
struct bpf_prog *to);
14041404
/* Called only from JIT-enabled code, so there's no need for stubs. */
1405-
void bpf_image_ksym_add(void *data, unsigned int size, struct bpf_ksym *ksym);
1405+
void bpf_image_ksym_init(void *data, unsigned int size, struct bpf_ksym *ksym);
1406+
void bpf_image_ksym_add(struct bpf_ksym *ksym);
14061407
void bpf_image_ksym_del(struct bpf_ksym *ksym);
14071408
void bpf_ksym_add(struct bpf_ksym *ksym);
14081409
void bpf_ksym_del(struct bpf_ksym *ksym);

kernel/bpf/bpf_struct_ops.c

Lines changed: 103 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ struct bpf_struct_ops_value {
2323

2424
struct bpf_struct_ops_map {
2525
struct bpf_map map;
26-
struct rcu_head rcu;
2726
const struct bpf_struct_ops_desc *st_ops_desc;
2827
/* protect map_update */
2928
struct mutex lock;
@@ -32,7 +31,9 @@ struct bpf_struct_ops_map {
3231
* (in kvalue.data).
3332
*/
3433
struct bpf_link **links;
35-
u32 links_cnt;
34+
/* ksyms for bpf trampolines */
35+
struct bpf_ksym **ksyms;
36+
u32 funcs_cnt;
3637
u32 image_pages_cnt;
3738
/* image_pages is an array of pages that has all the trampolines
3839
* that stores the func args before calling the bpf_prog.
@@ -481,11 +482,11 @@ static void bpf_struct_ops_map_put_progs(struct bpf_struct_ops_map *st_map)
481482
{
482483
u32 i;
483484

484-
for (i = 0; i < st_map->links_cnt; i++) {
485-
if (st_map->links[i]) {
486-
bpf_link_put(st_map->links[i]);
487-
st_map->links[i] = NULL;
488-
}
485+
for (i = 0; i < st_map->funcs_cnt; i++) {
486+
if (!st_map->links[i])
487+
break;
488+
bpf_link_put(st_map->links[i]);
489+
st_map->links[i] = NULL;
489490
}
490491
}
491492

@@ -586,6 +587,49 @@ int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_links *tlinks,
586587
return 0;
587588
}
588589

590+
static void bpf_struct_ops_ksym_init(const char *tname, const char *mname,
591+
void *image, unsigned int size,
592+
struct bpf_ksym *ksym)
593+
{
594+
snprintf(ksym->name, KSYM_NAME_LEN, "bpf__%s_%s", tname, mname);
595+
INIT_LIST_HEAD_RCU(&ksym->lnode);
596+
bpf_image_ksym_init(image, size, ksym);
597+
}
598+
599+
static void bpf_struct_ops_map_add_ksyms(struct bpf_struct_ops_map *st_map)
600+
{
601+
u32 i;
602+
603+
for (i = 0; i < st_map->funcs_cnt; i++) {
604+
if (!st_map->ksyms[i])
605+
break;
606+
bpf_image_ksym_add(st_map->ksyms[i]);
607+
}
608+
}
609+
610+
static void bpf_struct_ops_map_del_ksyms(struct bpf_struct_ops_map *st_map)
611+
{
612+
u32 i;
613+
614+
for (i = 0; i < st_map->funcs_cnt; i++) {
615+
if (!st_map->ksyms[i])
616+
break;
617+
bpf_image_ksym_del(st_map->ksyms[i]);
618+
}
619+
}
620+
621+
static void bpf_struct_ops_map_free_ksyms(struct bpf_struct_ops_map *st_map)
622+
{
623+
u32 i;
624+
625+
for (i = 0; i < st_map->funcs_cnt; i++) {
626+
if (!st_map->ksyms[i])
627+
break;
628+
kfree(st_map->ksyms[i]);
629+
st_map->ksyms[i] = NULL;
630+
}
631+
}
632+
589633
static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
590634
void *value, u64 flags)
591635
{
@@ -601,6 +645,9 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
601645
int prog_fd, err;
602646
u32 i, trampoline_start, image_off = 0;
603647
void *cur_image = NULL, *image = NULL;
648+
struct bpf_link **plink;
649+
struct bpf_ksym **pksym;
650+
const char *tname, *mname;
604651

605652
if (flags)
606653
return -EINVAL;
@@ -639,14 +686,19 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
639686
udata = &uvalue->data;
640687
kdata = &kvalue->data;
641688

689+
plink = st_map->links;
690+
pksym = st_map->ksyms;
691+
tname = btf_name_by_offset(st_map->btf, t->name_off);
642692
module_type = btf_type_by_id(btf_vmlinux, st_ops_ids[IDX_MODULE_ID]);
643693
for_each_member(i, t, member) {
644694
const struct btf_type *mtype, *ptype;
645695
struct bpf_prog *prog;
646696
struct bpf_tramp_link *link;
697+
struct bpf_ksym *ksym;
647698
u32 moff;
648699

649700
moff = __btf_member_bit_offset(t, member) / 8;
701+
mname = btf_name_by_offset(st_map->btf, member->name_off);
650702
ptype = btf_type_resolve_ptr(st_map->btf, member->type, NULL);
651703
if (ptype == module_type) {
652704
if (*(void **)(udata + moff))
@@ -714,7 +766,14 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
714766
}
715767
bpf_link_init(&link->link, BPF_LINK_TYPE_STRUCT_OPS,
716768
&bpf_struct_ops_link_lops, prog);
717-
st_map->links[i] = &link->link;
769+
*plink++ = &link->link;
770+
771+
ksym = kzalloc(sizeof(*ksym), GFP_USER);
772+
if (!ksym) {
773+
err = -ENOMEM;
774+
goto reset_unlock;
775+
}
776+
*pksym++ = ksym;
718777

719778
trampoline_start = image_off;
720779
err = bpf_struct_ops_prepare_trampoline(tlinks, link,
@@ -735,6 +794,12 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
735794

736795
/* put prog_id to udata */
737796
*(unsigned long *)(udata + moff) = prog->aux->id;
797+
798+
/* init ksym for this trampoline */
799+
bpf_struct_ops_ksym_init(tname, mname,
800+
image + trampoline_start,
801+
image_off - trampoline_start,
802+
ksym);
738803
}
739804

740805
if (st_ops->validate) {
@@ -783,13 +848,16 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
783848
*/
784849

785850
reset_unlock:
851+
bpf_struct_ops_map_free_ksyms(st_map);
786852
bpf_struct_ops_map_free_image(st_map);
787853
bpf_struct_ops_map_put_progs(st_map);
788854
memset(uvalue, 0, map->value_size);
789855
memset(kvalue, 0, map->value_size);
790856
unlock:
791857
kfree(tlinks);
792858
mutex_unlock(&st_map->lock);
859+
if (!err)
860+
bpf_struct_ops_map_add_ksyms(st_map);
793861
return err;
794862
}
795863

@@ -849,7 +917,10 @@ static void __bpf_struct_ops_map_free(struct bpf_map *map)
849917

850918
if (st_map->links)
851919
bpf_struct_ops_map_put_progs(st_map);
920+
if (st_map->ksyms)
921+
bpf_struct_ops_map_free_ksyms(st_map);
852922
bpf_map_area_free(st_map->links);
923+
bpf_map_area_free(st_map->ksyms);
853924
bpf_struct_ops_map_free_image(st_map);
854925
bpf_map_area_free(st_map->uvalue);
855926
bpf_map_area_free(st_map);
@@ -866,6 +937,8 @@ static void bpf_struct_ops_map_free(struct bpf_map *map)
866937
if (btf_is_module(st_map->btf))
867938
module_put(st_map->st_ops_desc->st_ops->owner);
868939

940+
bpf_struct_ops_map_del_ksyms(st_map);
941+
869942
/* The struct_ops's function may switch to another struct_ops.
870943
*
871944
* For example, bpf_tcp_cc_x->init() may switch to
@@ -895,6 +968,19 @@ static int bpf_struct_ops_map_alloc_check(union bpf_attr *attr)
895968
return 0;
896969
}
897970

971+
static u32 count_func_ptrs(const struct btf *btf, const struct btf_type *t)
972+
{
973+
int i;
974+
u32 count;
975+
const struct btf_member *member;
976+
977+
count = 0;
978+
for_each_member(i, t, member)
979+
if (btf_type_resolve_func_ptr(btf, member->type, NULL))
980+
count++;
981+
return count;
982+
}
983+
898984
static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
899985
{
900986
const struct bpf_struct_ops_desc *st_ops_desc;
@@ -961,11 +1047,15 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
9611047
map = &st_map->map;
9621048

9631049
st_map->uvalue = bpf_map_area_alloc(vt->size, NUMA_NO_NODE);
964-
st_map->links_cnt = btf_type_vlen(t);
1050+
st_map->funcs_cnt = count_func_ptrs(btf, t);
9651051
st_map->links =
966-
bpf_map_area_alloc(st_map->links_cnt * sizeof(struct bpf_links *),
1052+
bpf_map_area_alloc(st_map->funcs_cnt * sizeof(struct bpf_link *),
1053+
NUMA_NO_NODE);
1054+
1055+
st_map->ksyms =
1056+
bpf_map_area_alloc(st_map->funcs_cnt * sizeof(struct bpf_ksym *),
9671057
NUMA_NO_NODE);
968-
if (!st_map->uvalue || !st_map->links) {
1058+
if (!st_map->uvalue || !st_map->links || !st_map->ksyms) {
9691059
ret = -ENOMEM;
9701060
goto errout_free;
9711061
}
@@ -994,7 +1084,8 @@ static u64 bpf_struct_ops_map_mem_usage(const struct bpf_map *map)
9941084
usage = sizeof(*st_map) +
9951085
vt->size - sizeof(struct bpf_struct_ops_value);
9961086
usage += vt->size;
997-
usage += btf_type_vlen(vt) * sizeof(struct bpf_links *);
1087+
usage += st_map->funcs_cnt * sizeof(struct bpf_link *);
1088+
usage += st_map->funcs_cnt * sizeof(struct bpf_ksym *);
9981089
usage += PAGE_SIZE;
9991090
return usage;
10001091
}

kernel/bpf/dispatcher.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,8 @@ void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from,
154154
d->image = NULL;
155155
goto out;
156156
}
157-
bpf_image_ksym_add(d->image, PAGE_SIZE, &d->ksym);
157+
bpf_image_ksym_init(d->image, PAGE_SIZE, &d->ksym);
158+
bpf_image_ksym_add(&d->ksym);
158159
}
159160

160161
prev_num_progs = d->num_progs;

kernel/bpf/trampoline.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,14 @@ bool bpf_prog_has_trampoline(const struct bpf_prog *prog)
115115
(ptype == BPF_PROG_TYPE_LSM && eatype == BPF_LSM_MAC);
116116
}
117117

118-
void bpf_image_ksym_add(void *data, unsigned int size, struct bpf_ksym *ksym)
118+
void bpf_image_ksym_init(void *data, unsigned int size, struct bpf_ksym *ksym)
119119
{
120120
ksym->start = (unsigned long) data;
121121
ksym->end = ksym->start + size;
122+
}
123+
124+
void bpf_image_ksym_add(struct bpf_ksym *ksym)
125+
{
122126
bpf_ksym_add(ksym);
123127
perf_event_ksymbol(PERF_RECORD_KSYMBOL_TYPE_BPF, ksym->start,
124128
PAGE_SIZE, false, ksym->name);
@@ -377,7 +381,8 @@ static struct bpf_tramp_image *bpf_tramp_image_alloc(u64 key, int size)
377381
ksym = &im->ksym;
378382
INIT_LIST_HEAD_RCU(&ksym->lnode);
379383
snprintf(ksym->name, KSYM_NAME_LEN, "bpf_trampoline_%llu", key);
380-
bpf_image_ksym_add(image, size, ksym);
384+
bpf_image_ksym_init(image, size, ksym);
385+
bpf_image_ksym_add(ksym);
381386
return im;
382387

383388
out_free_image:

0 commit comments

Comments
 (0)