Skip to content

Commit f7e0bea

Browse files
Kui-Feng Leeanakryiko
authored andcommitted
bpf, x86: Generate trampolines from bpf_tramp_links
Replace struct bpf_tramp_progs with struct bpf_tramp_links to collect struct bpf_tramp_link(s) for a trampoline. struct bpf_tramp_link extends bpf_link to act as a linked list node. arch_prepare_bpf_trampoline() accepts a struct bpf_tramp_links to collects all bpf_tramp_link(s) that a trampoline should call. Change BPF trampoline and bpf_struct_ops to pass bpf_tramp_links instead of bpf_tramp_progs. Signed-off-by: Kui-Feng Lee <kuifeng@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Acked-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20220510205923.3206889-2-kuifeng@fb.com
1 parent cb41154 commit f7e0bea

File tree

10 files changed

+164
-103
lines changed

10 files changed

+164
-103
lines changed

arch/x86/net/bpf_jit_comp.c

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,10 +1762,12 @@ static void restore_regs(const struct btf_func_model *m, u8 **prog, int nr_args,
17621762
}
17631763

17641764
static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog,
1765-
struct bpf_prog *p, int stack_size, bool save_ret)
1765+
struct bpf_tramp_link *l, int stack_size,
1766+
bool save_ret)
17661767
{
17671768
u8 *prog = *pprog;
17681769
u8 *jmp_insn;
1770+
struct bpf_prog *p = l->link.prog;
17691771

17701772
/* arg1: mov rdi, progs[i] */
17711773
emit_mov_imm64(&prog, BPF_REG_1, (long) p >> 32, (u32) (long) p);
@@ -1850,14 +1852,14 @@ static int emit_cond_near_jump(u8 **pprog, void *func, void *ip, u8 jmp_cond)
18501852
}
18511853

18521854
static int invoke_bpf(const struct btf_func_model *m, u8 **pprog,
1853-
struct bpf_tramp_progs *tp, int stack_size,
1855+
struct bpf_tramp_links *tl, int stack_size,
18541856
bool save_ret)
18551857
{
18561858
int i;
18571859
u8 *prog = *pprog;
18581860

1859-
for (i = 0; i < tp->nr_progs; i++) {
1860-
if (invoke_bpf_prog(m, &prog, tp->progs[i], stack_size,
1861+
for (i = 0; i < tl->nr_links; i++) {
1862+
if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size,
18611863
save_ret))
18621864
return -EINVAL;
18631865
}
@@ -1866,7 +1868,7 @@ static int invoke_bpf(const struct btf_func_model *m, u8 **pprog,
18661868
}
18671869

18681870
static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog,
1869-
struct bpf_tramp_progs *tp, int stack_size,
1871+
struct bpf_tramp_links *tl, int stack_size,
18701872
u8 **branches)
18711873
{
18721874
u8 *prog = *pprog;
@@ -1877,8 +1879,8 @@ static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog,
18771879
*/
18781880
emit_mov_imm32(&prog, false, BPF_REG_0, 0);
18791881
emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -8);
1880-
for (i = 0; i < tp->nr_progs; i++) {
1881-
if (invoke_bpf_prog(m, &prog, tp->progs[i], stack_size, true))
1882+
for (i = 0; i < tl->nr_links; i++) {
1883+
if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, true))
18821884
return -EINVAL;
18831885

18841886
/* mod_ret prog stored return value into [rbp - 8]. Emit:
@@ -1980,14 +1982,14 @@ static bool is_valid_bpf_tramp_flags(unsigned int flags)
19801982
*/
19811983
int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end,
19821984
const struct btf_func_model *m, u32 flags,
1983-
struct bpf_tramp_progs *tprogs,
1985+
struct bpf_tramp_links *tlinks,
19841986
void *orig_call)
19851987
{
19861988
int ret, i, nr_args = m->nr_args;
19871989
int regs_off, ip_off, args_off, stack_size = nr_args * 8;
1988-
struct bpf_tramp_progs *fentry = &tprogs[BPF_TRAMP_FENTRY];
1989-
struct bpf_tramp_progs *fexit = &tprogs[BPF_TRAMP_FEXIT];
1990-
struct bpf_tramp_progs *fmod_ret = &tprogs[BPF_TRAMP_MODIFY_RETURN];
1990+
struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY];
1991+
struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT];
1992+
struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN];
19911993
u8 **branches = NULL;
19921994
u8 *prog;
19931995
bool save_ret;
@@ -2078,13 +2080,13 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
20782080
}
20792081
}
20802082

2081-
if (fentry->nr_progs)
2083+
if (fentry->nr_links)
20822084
if (invoke_bpf(m, &prog, fentry, regs_off,
20832085
flags & BPF_TRAMP_F_RET_FENTRY_RET))
20842086
return -EINVAL;
20852087

2086-
if (fmod_ret->nr_progs) {
2087-
branches = kcalloc(fmod_ret->nr_progs, sizeof(u8 *),
2088+
if (fmod_ret->nr_links) {
2089+
branches = kcalloc(fmod_ret->nr_links, sizeof(u8 *),
20882090
GFP_KERNEL);
20892091
if (!branches)
20902092
return -ENOMEM;
@@ -2111,7 +2113,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
21112113
prog += X86_PATCH_SIZE;
21122114
}
21132115

2114-
if (fmod_ret->nr_progs) {
2116+
if (fmod_ret->nr_links) {
21152117
/* From Intel 64 and IA-32 Architectures Optimization
21162118
* Reference Manual, 3.4.1.4 Code Alignment, Assembly/Compiler
21172119
* Coding Rule 11: All branch targets should be 16-byte
@@ -2121,12 +2123,12 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
21212123
/* Update the branches saved in invoke_bpf_mod_ret with the
21222124
* aligned address of do_fexit.
21232125
*/
2124-
for (i = 0; i < fmod_ret->nr_progs; i++)
2126+
for (i = 0; i < fmod_ret->nr_links; i++)
21252127
emit_cond_near_jump(&branches[i], prog, branches[i],
21262128
X86_JNE);
21272129
}
21282130

2129-
if (fexit->nr_progs)
2131+
if (fexit->nr_links)
21302132
if (invoke_bpf(m, &prog, fexit, regs_off, false)) {
21312133
ret = -EINVAL;
21322134
goto cleanup;

include/linux/bpf.h

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -723,11 +723,11 @@ struct btf_func_model {
723723
/* Each call __bpf_prog_enter + call bpf_func + call __bpf_prog_exit is ~50
724724
* bytes on x86. Pick a number to fit into BPF_IMAGE_SIZE / 2
725725
*/
726-
#define BPF_MAX_TRAMP_PROGS 38
726+
#define BPF_MAX_TRAMP_LINKS 38
727727

728-
struct bpf_tramp_progs {
729-
struct bpf_prog *progs[BPF_MAX_TRAMP_PROGS];
730-
int nr_progs;
728+
struct bpf_tramp_links {
729+
struct bpf_tramp_link *links[BPF_MAX_TRAMP_LINKS];
730+
int nr_links;
731731
};
732732

733733
/* Different use cases for BPF trampoline:
@@ -753,7 +753,7 @@ struct bpf_tramp_progs {
753753
struct bpf_tramp_image;
754754
int arch_prepare_bpf_trampoline(struct bpf_tramp_image *tr, void *image, void *image_end,
755755
const struct btf_func_model *m, u32 flags,
756-
struct bpf_tramp_progs *tprogs,
756+
struct bpf_tramp_links *tlinks,
757757
void *orig_call);
758758
/* these two functions are called from generated trampoline */
759759
u64 notrace __bpf_prog_enter(struct bpf_prog *prog);
@@ -852,9 +852,10 @@ static __always_inline __nocfi unsigned int bpf_dispatcher_nop_func(
852852
{
853853
return bpf_func(ctx, insnsi);
854854
}
855+
855856
#ifdef CONFIG_BPF_JIT
856-
int bpf_trampoline_link_prog(struct bpf_prog *prog, struct bpf_trampoline *tr);
857-
int bpf_trampoline_unlink_prog(struct bpf_prog *prog, struct bpf_trampoline *tr);
857+
int bpf_trampoline_link_prog(struct bpf_tramp_link *link, struct bpf_trampoline *tr);
858+
int bpf_trampoline_unlink_prog(struct bpf_tramp_link *link, struct bpf_trampoline *tr);
858859
struct bpf_trampoline *bpf_trampoline_get(u64 key,
859860
struct bpf_attach_target_info *tgt_info);
860861
void bpf_trampoline_put(struct bpf_trampoline *tr);
@@ -905,12 +906,12 @@ int bpf_jit_charge_modmem(u32 size);
905906
void bpf_jit_uncharge_modmem(u32 size);
906907
bool bpf_prog_has_trampoline(const struct bpf_prog *prog);
907908
#else
908-
static inline int bpf_trampoline_link_prog(struct bpf_prog *prog,
909+
static inline int bpf_trampoline_link_prog(struct bpf_tramp_link *link,
909910
struct bpf_trampoline *tr)
910911
{
911912
return -ENOTSUPP;
912913
}
913-
static inline int bpf_trampoline_unlink_prog(struct bpf_prog *prog,
914+
static inline int bpf_trampoline_unlink_prog(struct bpf_tramp_link *link,
914915
struct bpf_trampoline *tr)
915916
{
916917
return -ENOTSUPP;
@@ -1009,7 +1010,6 @@ struct bpf_prog_aux {
10091010
bool tail_call_reachable;
10101011
bool xdp_has_frags;
10111012
bool use_bpf_prog_pack;
1012-
struct hlist_node tramp_hlist;
10131013
/* BTF_KIND_FUNC_PROTO for valid attach_btf_id */
10141014
const struct btf_type *attach_func_proto;
10151015
/* function name for valid attach_btf_id */
@@ -1096,6 +1096,18 @@ struct bpf_link_ops {
10961096
struct bpf_link_info *info);
10971097
};
10981098

1099+
struct bpf_tramp_link {
1100+
struct bpf_link link;
1101+
struct hlist_node tramp_hlist;
1102+
};
1103+
1104+
struct bpf_tracing_link {
1105+
struct bpf_tramp_link link;
1106+
enum bpf_attach_type attach_type;
1107+
struct bpf_trampoline *trampoline;
1108+
struct bpf_prog *tgt_prog;
1109+
};
1110+
10991111
struct bpf_link_primer {
11001112
struct bpf_link *link;
11011113
struct file *file;
@@ -1133,8 +1145,8 @@ bool bpf_struct_ops_get(const void *kdata);
11331145
void bpf_struct_ops_put(const void *kdata);
11341146
int bpf_struct_ops_map_sys_lookup_elem(struct bpf_map *map, void *key,
11351147
void *value);
1136-
int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_progs *tprogs,
1137-
struct bpf_prog *prog,
1148+
int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_links *tlinks,
1149+
struct bpf_tramp_link *link,
11381150
const struct btf_func_model *model,
11391151
void *image, void *image_end);
11401152
static inline bool bpf_try_module_get(const void *data, struct module *owner)

include/linux/bpf_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,4 @@ BPF_LINK_TYPE(BPF_LINK_TYPE_XDP, xdp)
141141
BPF_LINK_TYPE(BPF_LINK_TYPE_PERF_EVENT, perf)
142142
#endif
143143
BPF_LINK_TYPE(BPF_LINK_TYPE_KPROBE_MULTI, kprobe_multi)
144+
BPF_LINK_TYPE(BPF_LINK_TYPE_STRUCT_OPS, struct_ops)

include/uapi/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,7 @@ enum bpf_link_type {
10131013
BPF_LINK_TYPE_XDP = 6,
10141014
BPF_LINK_TYPE_PERF_EVENT = 7,
10151015
BPF_LINK_TYPE_KPROBE_MULTI = 8,
1016+
BPF_LINK_TYPE_STRUCT_OPS = 9,
10161017

10171018
MAX_BPF_LINK_TYPE,
10181019
};

kernel/bpf/bpf_struct_ops.c

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ struct bpf_struct_ops_map {
3333
const struct bpf_struct_ops *st_ops;
3434
/* protect map_update */
3535
struct mutex lock;
36-
/* progs has all the bpf_prog that is populated
36+
/* link has all the bpf_links that is populated
3737
* to the func ptr of the kernel's struct
3838
* (in kvalue.data).
3939
*/
40-
struct bpf_prog **progs;
40+
struct bpf_link **links;
4141
/* image is a page that has all the trampolines
4242
* that stores the func args before calling the bpf_prog.
4343
* A PAGE_SIZE "image" is enough to store all trampoline for
44-
* "progs[]".
44+
* "links[]".
4545
*/
4646
void *image;
4747
/* uvalue->data stores the kernel struct
@@ -283,9 +283,9 @@ static void bpf_struct_ops_map_put_progs(struct bpf_struct_ops_map *st_map)
283283
u32 i;
284284

285285
for (i = 0; i < btf_type_vlen(t); i++) {
286-
if (st_map->progs[i]) {
287-
bpf_prog_put(st_map->progs[i]);
288-
st_map->progs[i] = NULL;
286+
if (st_map->links[i]) {
287+
bpf_link_put(st_map->links[i]);
288+
st_map->links[i] = NULL;
289289
}
290290
}
291291
}
@@ -316,18 +316,34 @@ static int check_zero_holes(const struct btf_type *t, void *data)
316316
return 0;
317317
}
318318

319-
int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_progs *tprogs,
320-
struct bpf_prog *prog,
319+
static void bpf_struct_ops_link_release(struct bpf_link *link)
320+
{
321+
}
322+
323+
static void bpf_struct_ops_link_dealloc(struct bpf_link *link)
324+
{
325+
struct bpf_tramp_link *tlink = container_of(link, struct bpf_tramp_link, link);
326+
327+
kfree(tlink);
328+
}
329+
330+
const struct bpf_link_ops bpf_struct_ops_link_lops = {
331+
.release = bpf_struct_ops_link_release,
332+
.dealloc = bpf_struct_ops_link_dealloc,
333+
};
334+
335+
int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_links *tlinks,
336+
struct bpf_tramp_link *link,
321337
const struct btf_func_model *model,
322338
void *image, void *image_end)
323339
{
324340
u32 flags;
325341

326-
tprogs[BPF_TRAMP_FENTRY].progs[0] = prog;
327-
tprogs[BPF_TRAMP_FENTRY].nr_progs = 1;
342+
tlinks[BPF_TRAMP_FENTRY].links[0] = link;
343+
tlinks[BPF_TRAMP_FENTRY].nr_links = 1;
328344
flags = model->ret_size > 0 ? BPF_TRAMP_F_RET_FENTRY_RET : 0;
329345
return arch_prepare_bpf_trampoline(NULL, image, image_end,
330-
model, flags, tprogs, NULL);
346+
model, flags, tlinks, NULL);
331347
}
332348

333349
static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
@@ -338,7 +354,7 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
338354
struct bpf_struct_ops_value *uvalue, *kvalue;
339355
const struct btf_member *member;
340356
const struct btf_type *t = st_ops->type;
341-
struct bpf_tramp_progs *tprogs = NULL;
357+
struct bpf_tramp_links *tlinks = NULL;
342358
void *udata, *kdata;
343359
int prog_fd, err = 0;
344360
void *image, *image_end;
@@ -362,8 +378,8 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
362378
if (uvalue->state || refcount_read(&uvalue->refcnt))
363379
return -EINVAL;
364380

365-
tprogs = kcalloc(BPF_TRAMP_MAX, sizeof(*tprogs), GFP_KERNEL);
366-
if (!tprogs)
381+
tlinks = kcalloc(BPF_TRAMP_MAX, sizeof(*tlinks), GFP_KERNEL);
382+
if (!tlinks)
367383
return -ENOMEM;
368384

369385
uvalue = (struct bpf_struct_ops_value *)st_map->uvalue;
@@ -386,6 +402,7 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
386402
for_each_member(i, t, member) {
387403
const struct btf_type *mtype, *ptype;
388404
struct bpf_prog *prog;
405+
struct bpf_tramp_link *link;
389406
u32 moff;
390407

391408
moff = __btf_member_bit_offset(t, member) / 8;
@@ -439,16 +456,26 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
439456
err = PTR_ERR(prog);
440457
goto reset_unlock;
441458
}
442-
st_map->progs[i] = prog;
443459

444460
if (prog->type != BPF_PROG_TYPE_STRUCT_OPS ||
445461
prog->aux->attach_btf_id != st_ops->type_id ||
446462
prog->expected_attach_type != i) {
463+
bpf_prog_put(prog);
447464
err = -EINVAL;
448465
goto reset_unlock;
449466
}
450467

451-
err = bpf_struct_ops_prepare_trampoline(tprogs, prog,
468+
link = kzalloc(sizeof(*link), GFP_USER);
469+
if (!link) {
470+
bpf_prog_put(prog);
471+
err = -ENOMEM;
472+
goto reset_unlock;
473+
}
474+
bpf_link_init(&link->link, BPF_LINK_TYPE_STRUCT_OPS,
475+
&bpf_struct_ops_link_lops, prog);
476+
st_map->links[i] = &link->link;
477+
478+
err = bpf_struct_ops_prepare_trampoline(tlinks, link,
452479
&st_ops->func_models[i],
453480
image, image_end);
454481
if (err < 0)
@@ -491,7 +518,7 @@ static int bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
491518
memset(uvalue, 0, map->value_size);
492519
memset(kvalue, 0, map->value_size);
493520
unlock:
494-
kfree(tprogs);
521+
kfree(tlinks);
495522
mutex_unlock(&st_map->lock);
496523
return err;
497524
}
@@ -546,9 +573,9 @@ static void bpf_struct_ops_map_free(struct bpf_map *map)
546573
{
547574
struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map;
548575

549-
if (st_map->progs)
576+
if (st_map->links)
550577
bpf_struct_ops_map_put_progs(st_map);
551-
bpf_map_area_free(st_map->progs);
578+
bpf_map_area_free(st_map->links);
552579
bpf_jit_free_exec(st_map->image);
553580
bpf_map_area_free(st_map->uvalue);
554581
bpf_map_area_free(st_map);
@@ -597,11 +624,11 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
597624
map = &st_map->map;
598625

599626
st_map->uvalue = bpf_map_area_alloc(vt->size, NUMA_NO_NODE);
600-
st_map->progs =
601-
bpf_map_area_alloc(btf_type_vlen(t) * sizeof(struct bpf_prog *),
627+
st_map->links =
628+
bpf_map_area_alloc(btf_type_vlen(t) * sizeof(struct bpf_links *),
602629
NUMA_NO_NODE);
603630
st_map->image = bpf_jit_alloc_exec(PAGE_SIZE);
604-
if (!st_map->uvalue || !st_map->progs || !st_map->image) {
631+
if (!st_map->uvalue || !st_map->links || !st_map->image) {
605632
bpf_struct_ops_map_free(map);
606633
return ERR_PTR(-ENOMEM);
607634
}

0 commit comments

Comments
 (0)