Skip to content

Commit 2d419c4

Browse files
image-dragonAlexei Starovoitov
authored andcommitted
bpf: add fsession support
The fsession is something that similar to kprobe session. It allow to attach a single BPF program to both the entry and the exit of the target functions. Introduce the struct bpf_fsession_link, which allows to add the link to both the fentry and fexit progs_hlist of the trampoline. Signed-off-by: Menglong Dong <dongml2@chinatelecom.cn> Co-developed-by: Leon Hwang <leon.hwang@linux.dev> Signed-off-by: Leon Hwang <leon.hwang@linux.dev> Link: https://lore.kernel.org/r/20260124062008.8657-2-dongml2@chinatelecom.cn Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent c7900f2 commit 2d419c4

File tree

10 files changed

+97
-13
lines changed

10 files changed

+97
-13
lines changed

include/linux/bpf.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,7 @@ enum bpf_tramp_prog_type {
13091309
BPF_TRAMP_MODIFY_RETURN,
13101310
BPF_TRAMP_MAX,
13111311
BPF_TRAMP_REPLACE, /* more than MAX */
1312+
BPF_TRAMP_FSESSION,
13121313
};
13131314

13141315
struct bpf_tramp_image {
@@ -1875,6 +1876,11 @@ struct bpf_tracing_link {
18751876
struct bpf_prog *tgt_prog;
18761877
};
18771878

1879+
struct bpf_fsession_link {
1880+
struct bpf_tracing_link link;
1881+
struct bpf_tramp_link fexit;
1882+
};
1883+
18781884
struct bpf_raw_tp_link {
18791885
struct bpf_link link;
18801886
struct bpf_raw_event_map *btp;
@@ -2169,6 +2175,19 @@ static inline void bpf_struct_ops_desc_release(struct bpf_struct_ops_desc *st_op
21692175

21702176
#endif
21712177

2178+
static inline int bpf_fsession_cnt(struct bpf_tramp_links *links)
2179+
{
2180+
struct bpf_tramp_links fentries = links[BPF_TRAMP_FENTRY];
2181+
int cnt = 0;
2182+
2183+
for (int i = 0; i < links[BPF_TRAMP_FENTRY].nr_links; i++) {
2184+
if (fentries.links[i]->link.prog->expected_attach_type == BPF_TRACE_FSESSION)
2185+
cnt++;
2186+
}
2187+
2188+
return cnt;
2189+
}
2190+
21722191
int bpf_prog_ctx_arg_info_init(struct bpf_prog *prog,
21732192
const struct bpf_ctx_arg_aux *info, u32 cnt);
21742193

include/uapi/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,7 @@ enum bpf_attach_type {
11451145
BPF_NETKIT_PEER,
11461146
BPF_TRACE_KPROBE_SESSION,
11471147
BPF_TRACE_UPROBE_SESSION,
1148+
BPF_TRACE_FSESSION,
11481149
__MAX_BPF_ATTACH_TYPE
11491150
};
11501151

kernel/bpf/btf.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6219,6 +6219,7 @@ static int btf_validate_prog_ctx_type(struct bpf_verifier_log *log, const struct
62196219
case BPF_TRACE_FENTRY:
62206220
case BPF_TRACE_FEXIT:
62216221
case BPF_MODIFY_RETURN:
6222+
case BPF_TRACE_FSESSION:
62226223
/* allow u64* as ctx */
62236224
if (btf_is_int(t) && t->size == 8)
62246225
return 0;
@@ -6820,6 +6821,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
68206821
fallthrough;
68216822
case BPF_LSM_CGROUP:
68226823
case BPF_TRACE_FEXIT:
6824+
case BPF_TRACE_FSESSION:
68236825
/* When LSM programs are attached to void LSM hooks
68246826
* they use FEXIT trampolines and when attached to
68256827
* int LSM hooks, they use MODIFY_RETURN trampolines.

kernel/bpf/syscall.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3577,6 +3577,7 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
35773577
case BPF_PROG_TYPE_TRACING:
35783578
if (prog->expected_attach_type != BPF_TRACE_FENTRY &&
35793579
prog->expected_attach_type != BPF_TRACE_FEXIT &&
3580+
prog->expected_attach_type != BPF_TRACE_FSESSION &&
35803581
prog->expected_attach_type != BPF_MODIFY_RETURN) {
35813582
err = -EINVAL;
35823583
goto out_put_prog;
@@ -3626,7 +3627,21 @@ static int bpf_tracing_prog_attach(struct bpf_prog *prog,
36263627
key = bpf_trampoline_compute_key(tgt_prog, NULL, btf_id);
36273628
}
36283629

3629-
link = kzalloc(sizeof(*link), GFP_USER);
3630+
if (prog->expected_attach_type == BPF_TRACE_FSESSION) {
3631+
struct bpf_fsession_link *fslink;
3632+
3633+
fslink = kzalloc(sizeof(*fslink), GFP_USER);
3634+
if (fslink) {
3635+
bpf_link_init(&fslink->fexit.link, BPF_LINK_TYPE_TRACING,
3636+
&bpf_tracing_link_lops, prog, attach_type);
3637+
fslink->fexit.cookie = bpf_cookie;
3638+
link = &fslink->link;
3639+
} else {
3640+
link = NULL;
3641+
}
3642+
} else {
3643+
link = kzalloc(sizeof(*link), GFP_USER);
3644+
}
36303645
if (!link) {
36313646
err = -ENOMEM;
36323647
goto out_put_prog;
@@ -4350,6 +4365,7 @@ attach_type_to_prog_type(enum bpf_attach_type attach_type)
43504365
case BPF_TRACE_RAW_TP:
43514366
case BPF_TRACE_FENTRY:
43524367
case BPF_TRACE_FEXIT:
4368+
case BPF_TRACE_FSESSION:
43534369
case BPF_MODIFY_RETURN:
43544370
return BPF_PROG_TYPE_TRACING;
43554371
case BPF_LSM_MAC:

kernel/bpf/trampoline.c

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,17 @@ bool bpf_prog_has_trampoline(const struct bpf_prog *prog)
109109
enum bpf_attach_type eatype = prog->expected_attach_type;
110110
enum bpf_prog_type ptype = prog->type;
111111

112-
return (ptype == BPF_PROG_TYPE_TRACING &&
113-
(eatype == BPF_TRACE_FENTRY || eatype == BPF_TRACE_FEXIT ||
114-
eatype == BPF_MODIFY_RETURN)) ||
115-
(ptype == BPF_PROG_TYPE_LSM && eatype == BPF_LSM_MAC);
112+
switch (ptype) {
113+
case BPF_PROG_TYPE_TRACING:
114+
if (eatype == BPF_TRACE_FENTRY || eatype == BPF_TRACE_FEXIT ||
115+
eatype == BPF_MODIFY_RETURN || eatype == BPF_TRACE_FSESSION)
116+
return true;
117+
return false;
118+
case BPF_PROG_TYPE_LSM:
119+
return eatype == BPF_LSM_MAC;
120+
default:
121+
return false;
122+
}
116123
}
117124

118125
void bpf_image_ksym_init(void *data, unsigned int size, struct bpf_ksym *ksym)
@@ -559,6 +566,8 @@ static enum bpf_tramp_prog_type bpf_attach_type_to_tramp(struct bpf_prog *prog)
559566
return BPF_TRAMP_MODIFY_RETURN;
560567
case BPF_TRACE_FEXIT:
561568
return BPF_TRAMP_FEXIT;
569+
case BPF_TRACE_FSESSION:
570+
return BPF_TRAMP_FSESSION;
562571
case BPF_LSM_MAC:
563572
if (!prog->aux->attach_func_proto->type)
564573
/* The function returns void, we cannot modify its
@@ -594,8 +603,10 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link,
594603
struct bpf_trampoline *tr,
595604
struct bpf_prog *tgt_prog)
596605
{
606+
struct bpf_fsession_link *fslink = NULL;
597607
enum bpf_tramp_prog_type kind;
598608
struct bpf_tramp_link *link_exiting;
609+
struct hlist_head *prog_list;
599610
int err = 0;
600611
int cnt = 0, i;
601612

@@ -621,24 +632,43 @@ static int __bpf_trampoline_link_prog(struct bpf_tramp_link *link,
621632
BPF_MOD_JUMP, NULL,
622633
link->link.prog->bpf_func);
623634
}
635+
if (kind == BPF_TRAMP_FSESSION) {
636+
prog_list = &tr->progs_hlist[BPF_TRAMP_FENTRY];
637+
cnt++;
638+
} else {
639+
prog_list = &tr->progs_hlist[kind];
640+
}
624641
if (cnt >= BPF_MAX_TRAMP_LINKS)
625642
return -E2BIG;
626643
if (!hlist_unhashed(&link->tramp_hlist))
627644
/* prog already linked */
628645
return -EBUSY;
629-
hlist_for_each_entry(link_exiting, &tr->progs_hlist[kind], tramp_hlist) {
646+
hlist_for_each_entry(link_exiting, prog_list, tramp_hlist) {
630647
if (link_exiting->link.prog != link->link.prog)
631648
continue;
632649
/* prog already linked */
633650
return -EBUSY;
634651
}
635652

636-
hlist_add_head(&link->tramp_hlist, &tr->progs_hlist[kind]);
637-
tr->progs_cnt[kind]++;
653+
hlist_add_head(&link->tramp_hlist, prog_list);
654+
if (kind == BPF_TRAMP_FSESSION) {
655+
tr->progs_cnt[BPF_TRAMP_FENTRY]++;
656+
fslink = container_of(link, struct bpf_fsession_link, link.link);
657+
hlist_add_head(&fslink->fexit.tramp_hlist, &tr->progs_hlist[BPF_TRAMP_FEXIT]);
658+
tr->progs_cnt[BPF_TRAMP_FEXIT]++;
659+
} else {
660+
tr->progs_cnt[kind]++;
661+
}
638662
err = bpf_trampoline_update(tr, true /* lock_direct_mutex */);
639663
if (err) {
640664
hlist_del_init(&link->tramp_hlist);
641-
tr->progs_cnt[kind]--;
665+
if (kind == BPF_TRAMP_FSESSION) {
666+
tr->progs_cnt[BPF_TRAMP_FENTRY]--;
667+
hlist_del_init(&fslink->fexit.tramp_hlist);
668+
tr->progs_cnt[BPF_TRAMP_FEXIT]--;
669+
} else {
670+
tr->progs_cnt[kind]--;
671+
}
642672
}
643673
return err;
644674
}
@@ -672,6 +702,13 @@ static int __bpf_trampoline_unlink_prog(struct bpf_tramp_link *link,
672702
guard(mutex)(&tgt_prog->aux->ext_mutex);
673703
tgt_prog->aux->is_extended = false;
674704
return err;
705+
} else if (kind == BPF_TRAMP_FSESSION) {
706+
struct bpf_fsession_link *fslink =
707+
container_of(link, struct bpf_fsession_link, link.link);
708+
709+
hlist_del_init(&fslink->fexit.tramp_hlist);
710+
tr->progs_cnt[BPF_TRAMP_FEXIT]--;
711+
kind = BPF_TRAMP_FENTRY;
675712
}
676713
hlist_del_init(&link->tramp_hlist);
677714
tr->progs_cnt[kind]--;

kernel/bpf/verifier.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17848,6 +17848,7 @@ static int check_return_code(struct bpf_verifier_env *env, int regno, const char
1784817848
switch (env->prog->expected_attach_type) {
1784917849
case BPF_TRACE_FENTRY:
1785017850
case BPF_TRACE_FEXIT:
17851+
case BPF_TRACE_FSESSION:
1785117852
range = retval_range(0, 0);
1785217853
break;
1785317854
case BPF_TRACE_RAW_TP:
@@ -23774,6 +23775,7 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
2377423775
if (prog_type == BPF_PROG_TYPE_TRACING &&
2377523776
insn->imm == BPF_FUNC_get_func_ret) {
2377623777
if (eatype == BPF_TRACE_FEXIT ||
23778+
eatype == BPF_TRACE_FSESSION ||
2377723779
eatype == BPF_MODIFY_RETURN) {
2377823780
/* Load nr_args from ctx - 8 */
2377923781
insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8);
@@ -24725,7 +24727,8 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
2472524727
if (tgt_prog->type == BPF_PROG_TYPE_TRACING &&
2472624728
prog_extension &&
2472724729
(tgt_prog->expected_attach_type == BPF_TRACE_FENTRY ||
24728-
tgt_prog->expected_attach_type == BPF_TRACE_FEXIT)) {
24730+
tgt_prog->expected_attach_type == BPF_TRACE_FEXIT ||
24731+
tgt_prog->expected_attach_type == BPF_TRACE_FSESSION)) {
2472924732
/* Program extensions can extend all program types
2473024733
* except fentry/fexit. The reason is the following.
2473124734
* The fentry/fexit programs are used for performance
@@ -24740,7 +24743,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
2474024743
* beyond reasonable stack size. Hence extending fentry
2474124744
* is not allowed.
2474224745
*/
24743-
bpf_log(log, "Cannot extend fentry/fexit\n");
24746+
bpf_log(log, "Cannot extend fentry/fexit/fsession\n");
2474424747
return -EINVAL;
2474524748
}
2474624749
} else {
@@ -24824,6 +24827,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
2482424827
case BPF_LSM_CGROUP:
2482524828
case BPF_TRACE_FENTRY:
2482624829
case BPF_TRACE_FEXIT:
24830+
case BPF_TRACE_FSESSION:
2482724831
if (!btf_type_is_func(t)) {
2482824832
bpf_log(log, "attach_btf_id %u is not a function\n",
2482924833
btf_id);
@@ -24990,6 +24994,7 @@ static bool can_be_sleepable(struct bpf_prog *prog)
2499024994
case BPF_TRACE_FEXIT:
2499124995
case BPF_MODIFY_RETURN:
2499224996
case BPF_TRACE_ITER:
24997+
case BPF_TRACE_FSESSION:
2499324998
return true;
2499424999
default:
2499525000
return false;
@@ -25071,9 +25076,10 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
2507125076
tgt_info.tgt_name);
2507225077
return -EINVAL;
2507325078
} else if ((prog->expected_attach_type == BPF_TRACE_FEXIT ||
25079+
prog->expected_attach_type == BPF_TRACE_FSESSION ||
2507425080
prog->expected_attach_type == BPF_MODIFY_RETURN) &&
2507525081
btf_id_set_contains(&noreturn_deny, btf_id)) {
25076-
verbose(env, "Attaching fexit/fmod_ret to __noreturn function '%s' is rejected.\n",
25082+
verbose(env, "Attaching fexit/fsession/fmod_ret to __noreturn function '%s' is rejected.\n",
2507725083
tgt_info.tgt_name);
2507825084
return -EINVAL;
2507925085
}

net/bpf/test_run.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@ int bpf_prog_test_run_tracing(struct bpf_prog *prog,
685685
switch (prog->expected_attach_type) {
686686
case BPF_TRACE_FENTRY:
687687
case BPF_TRACE_FEXIT:
688+
case BPF_TRACE_FSESSION:
688689
if (bpf_fentry_test1(1) != 2 ||
689690
bpf_fentry_test2(2, 3) != 5 ||
690691
bpf_fentry_test3(4, 5, 6) != 15 ||

net/core/bpf_sk_storage.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ static bool bpf_sk_storage_tracing_allowed(const struct bpf_prog *prog)
365365
return true;
366366
case BPF_TRACE_FENTRY:
367367
case BPF_TRACE_FEXIT:
368+
case BPF_TRACE_FSESSION:
368369
return !!strncmp(prog->aux->attach_func_name, "bpf_sk_storage",
369370
strlen("bpf_sk_storage"));
370371
default:

tools/include/uapi/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,7 @@ enum bpf_attach_type {
11451145
BPF_NETKIT_PEER,
11461146
BPF_TRACE_KPROBE_SESSION,
11471147
BPF_TRACE_UPROBE_SESSION,
1148+
BPF_TRACE_FSESSION,
11481149
__MAX_BPF_ATTACH_TYPE
11491150
};
11501151

tools/testing/selftests/bpf/prog_tests/tracing_failure.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ static void test_tracing_deny(void)
7373
static void test_fexit_noreturns(void)
7474
{
7575
test_tracing_fail_prog("fexit_noreturns",
76-
"Attaching fexit/fmod_ret to __noreturn function 'do_exit' is rejected.");
76+
"Attaching fexit/fsession/fmod_ret to __noreturn function 'do_exit' is rejected.");
7777
}
7878

7979
void test_tracing_failure(void)

0 commit comments

Comments
 (0)