Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'bpf-fsession-support'

Menglong Dong says:

====================
bpf: fsession support

overall
-------
Sometimes, we need to hook both the entry and exit of a function with
TRACING. Therefore, we need define a FENTRY and a FEXIT for the target
function, which is not convenient.

Therefore, we add a tracing session support for TRACING. Generally
speaking, it's similar to kprobe session, which can hook both the entry
and exit of a function with a single BPF program.

We allow the usage of bpf_get_func_ret() to get the return value in the
fentry of the tracing session, as it will always get "0", which is safe
enough and is OK.

Session cookie is also supported with the kfunc bpf_session_cookie().
In order to limit the stack usage, we limit the maximum number of cookies
to 4.

kfunc design
------------
In order to keep consistency with existing kfunc, we don't introduce new
kfunc for fsession. Instead, we reuse the existing kfunc
bpf_session_cookie() and bpf_session_is_return().

The prototype of bpf_session_cookie() and bpf_session_is_return() don't
satisfy our needs, so we change their prototype by adding the argument
"void *ctx" to them.

We inline bpf_session_cookie() and bpf_session_is_return() for fsession
in the verifier directly. Therefore, we don't need to introduce new
functions for them.

architecture
------------
The fsession stuff is arch related, so the -EOPNOTSUPP will be returned if
it is not supported yet by the arch. In this series, we only support
x86_64. And later, other arch will be implemented.

Changes v12 -> v13:
* fix the selftests fail on !x86_64 in the 11th patch
* v12: https://lore.kernel.org/bpf/20260124033119.28682-1-dongml2@chinatelecom.cn/

Changes v11 -> v12:
* update the variable "delta" in the 2nd patch
* improve the fsession testcase by adding the 11th patch, which will test
bpf_get_func_* for fsession
* v11: https://lore.kernel.org/bpf/20260123073532.238985-1-dongml2@chinatelecom.cn/

Changes v10 -> v11:
* rebase and fix the conflicts in the 2nd patch
* use "volatile" in the 11th patch
* rename BPF_TRAMP_SHIFT_* to BPF_TRAMP_*_SHIFT
* v10: https://lore.kernel.org/bpf/20260115112246.221082-1-dongml2@chinatelecom.cn/

Changes v9 -> v10:
* 1st patch: some small adjustment, such as use switch in
bpf_prog_has_trampoline()
* 2nd patch: some adjustment to the commit log and comment
* 3rd patch:
- drop the declaration of bpf_session_is_return() and
bpf_session_cookie()
- use vmlinux.h instead of bpf_kfuncs.h in uprobe_multi_session.c,
kprobe_multi_session_cookie.c and uprobe_multi_session_cookie.c
* 4th patch:
- some adjustment to the comment and commit log
- rename the prefix from BPF_TRAMP_M_ to BPF_TRAMP_SHIFT_
- remove the definition of BPF_TRAMP_M_NR_ARGS
- check the program type in bpf_session_filter()
* 5th patch: some adjustment to the commit log
* 6th patch:
- add the "reg" to the function arguments of emit_store_stack_imm64()
- use the positive offset in emit_store_stack_imm64()
* 7th patch:
- use "|" for func_meta instead of "+"
- pass the "func_meta_off" to invoke_bpf() explicitly, instead of
computing it with "stack_size + 8"
- pass the "cookie_off" to invoke_bpf() instead of computing the current
cookie index with "func_meta"
* 8th patch:
- split the modification to bpftool to a separate patch
* v9: https://lore.kernel.org/bpf/20260110141115.537055-1-dongml2@chinatelecom.cn/

Changes v8 -> v9:
* remove the definition of bpf_fsession_cookie and bpf_fsession_is_return
in the 4th and 5th patch
* rename emit_st_r0_imm64() to emit_store_stack_imm64() in the 6th patch
* v8: https://lore.kernel.org/bpf/20260108022450.88086-1-dongml2@chinatelecom.cn/

Changes v7 -> v8:
* use the last byte of nr_args for bpf_get_func_arg_cnt() in the 2nd patch
* v7: https://lore.kernel.org/bpf/20260107064352.291069-1-dongml2@chinatelecom.cn/

Changes v6 -> v7:
* change the prototype of bpf_session_cookie() and bpf_session_is_return(),
and reuse them instead of introduce new kfunc for fsession.
* v6: https://lore.kernel.org/bpf/20260104122814.183732-1-dongml2@chinatelecom.cn/

Changes v5 -> v6:
* No changes in this version, just a rebase to deal with conflicts.
* v5: https://lore.kernel.org/bpf/20251224130735.201422-1-dongml2@chinatelecom.cn/

Changes v4 -> v5:
* use fsession terminology consistently in all patches
* 1st patch:
- use more explicit way in __bpf_trampoline_link_prog()
* 4th patch:
- remove "cookie_cnt" in struct bpf_trampoline
* 6th patch:
- rename nr_regs to func_md
- define cookie_off in a new line
* 7th patch:
- remove the handling of BPF_TRACE_SESSION in legacy fallback path for
BPF_RAW_TRACEPOINT_OPEN
* v4: https://lore.kernel.org/bpf/20251217095445.218428-1-dongml2@chinatelecom.cn/

Changes v3 -> v4:
* instead of adding a new hlist to progs_hlist in trampoline, add the bpf
program to both the fentry hlist and the fexit hlist.
* introduce the 2nd patch to reuse the nr_args field in the stack to
store all the information we need(except the session cookies).
* limit the maximum number of cookies to 4.
* remove the logic to skip fexit if the fentry return non-zero.
* v3: https://lore.kernel.org/bpf/20251026030143.23807-1-dongml2@chinatelecom.cn/

Changes v2 -> v3:
* squeeze some patches:
- the 2 patches for the kfunc bpf_tracing_is_exit() and
bpf_fsession_cookie() are merged into the second patch.
- the testcases for fsession are also squeezed.
* fix the CI error by move the testcase for bpf_get_func_ip to
fsession_test.c
* v2: https://lore.kernel.org/bpf/20251022080159.553805-1-dongml2@chinatelecom.cn/

Changes v1 -> v2:
* session cookie support.
In this version, session cookie is implemented, and the kfunc
bpf_fsession_cookie() is added.
* restructure the layout of the stack.
In this version, the session stuff that stored in the stack is changed,
and we locate them after the return value to not break
bpf_get_func_ip().
* testcase enhancement.
Some nits in the testcase that suggested by Jiri is fixed. Meanwhile,
the testcase for get_func_ip and session cookie is added too.
* v1: https://lore.kernel.org/bpf/20251018142124.783206-1-dongml2@chinatelecom.cn/
====================

Link: https://patch.msgid.link/20260124062008.8657-1-dongml2@chinatelecom.cn
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+654 -101
+53 -23
arch/x86/net/bpf_jit_comp.c
··· 1300 1300 emit_st_index(pprog, size, dst_reg, X86_REG_R12, off, imm); 1301 1301 } 1302 1302 1303 + static void emit_store_stack_imm64(u8 **pprog, int reg, int stack_off, u64 imm64) 1304 + { 1305 + /* 1306 + * mov reg, imm64 1307 + * mov QWORD PTR [rbp + stack_off], reg 1308 + */ 1309 + emit_mov_imm64(pprog, reg, imm64 >> 32, (u32) imm64); 1310 + emit_stx(pprog, BPF_DW, BPF_REG_FP, reg, stack_off); 1311 + } 1312 + 1303 1313 static int emit_atomic_rmw(u8 **pprog, u32 atomic_op, 1304 1314 u32 dst_reg, u32 src_reg, s16 off, u8 bpf_size) 1305 1315 { ··· 3094 3084 3095 3085 static int invoke_bpf(const struct btf_func_model *m, u8 **pprog, 3096 3086 struct bpf_tramp_links *tl, int stack_size, 3097 - int run_ctx_off, bool save_ret, 3098 - void *image, void *rw_image) 3087 + int run_ctx_off, int func_meta_off, bool save_ret, 3088 + void *image, void *rw_image, u64 func_meta, 3089 + int cookie_off) 3099 3090 { 3100 - int i; 3091 + int i, cur_cookie = (cookie_off - stack_size) / 8; 3101 3092 u8 *prog = *pprog; 3102 3093 3103 3094 for (i = 0; i < tl->nr_links; i++) { 3095 + if (tl->links[i]->link.prog->call_session_cookie) { 3096 + emit_store_stack_imm64(&prog, BPF_REG_0, -func_meta_off, 3097 + func_meta | (cur_cookie << BPF_TRAMP_COOKIE_INDEX_SHIFT)); 3098 + cur_cookie--; 3099 + } 3104 3100 if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, 3105 3101 run_ctx_off, save_ret, image, rw_image)) 3106 3102 return -EINVAL; ··· 3224 3208 void *func_addr) 3225 3209 { 3226 3210 int i, ret, nr_regs = m->nr_args, stack_size = 0; 3227 - int regs_off, nregs_off, ip_off, run_ctx_off, arg_stack_off, rbx_off; 3211 + int regs_off, func_meta_off, ip_off, run_ctx_off, arg_stack_off, rbx_off; 3228 3212 struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY]; 3229 3213 struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT]; 3230 3214 struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN]; 3231 3215 void *orig_call = func_addr; 3216 + int cookie_off, cookie_cnt; 3232 3217 u8 **branches = NULL; 3218 + u64 func_meta; 3233 3219 u8 *prog; 3234 3220 bool save_ret; 3235 3221 ··· 3267 3249 * [ ... ] 3268 3250 * RBP - regs_off [ reg_arg1 ] program's ctx pointer 3269 3251 * 3270 - * RBP - nregs_off [ regs count ] always 3252 + * RBP - func_meta_off [ regs count, etc ] always 3271 3253 * 3272 3254 * RBP - ip_off [ traced function ] BPF_TRAMP_F_IP_ARG flag 3273 3255 * ··· 3290 3272 stack_size += nr_regs * 8; 3291 3273 regs_off = stack_size; 3292 3274 3293 - /* regs count */ 3275 + /* function matedata, such as regs count */ 3294 3276 stack_size += 8; 3295 - nregs_off = stack_size; 3277 + func_meta_off = stack_size; 3296 3278 3297 3279 if (flags & BPF_TRAMP_F_IP_ARG) 3298 3280 stack_size += 8; /* room for IP address argument */ 3299 3281 3300 3282 ip_off = stack_size; 3283 + 3284 + cookie_cnt = bpf_fsession_cookie_cnt(tlinks); 3285 + /* room for session cookies */ 3286 + stack_size += cookie_cnt * 8; 3287 + cookie_off = stack_size; 3301 3288 3302 3289 stack_size += 8; 3303 3290 rbx_off = stack_size; ··· 3371 3348 /* mov QWORD PTR [rbp - rbx_off], rbx */ 3372 3349 emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_6, -rbx_off); 3373 3350 3374 - /* Store number of argument registers of the traced function: 3375 - * mov rax, nr_regs 3376 - * mov QWORD PTR [rbp - nregs_off], rax 3377 - */ 3378 - emit_mov_imm64(&prog, BPF_REG_0, 0, (u32) nr_regs); 3379 - emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -nregs_off); 3351 + func_meta = nr_regs; 3352 + /* Store number of argument registers of the traced function */ 3353 + emit_store_stack_imm64(&prog, BPF_REG_0, -func_meta_off, func_meta); 3380 3354 3381 3355 if (flags & BPF_TRAMP_F_IP_ARG) { 3382 - /* Store IP address of the traced function: 3383 - * movabsq rax, func_addr 3384 - * mov QWORD PTR [rbp - ip_off], rax 3385 - */ 3386 - emit_mov_imm64(&prog, BPF_REG_0, (long) func_addr >> 32, (u32) (long) func_addr); 3387 - emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -ip_off); 3356 + /* Store IP address of the traced function */ 3357 + emit_store_stack_imm64(&prog, BPF_REG_0, -ip_off, (long)func_addr); 3388 3358 } 3389 3359 3390 3360 save_args(m, &prog, regs_off, false, flags); ··· 3392 3376 } 3393 3377 } 3394 3378 3379 + if (bpf_fsession_cnt(tlinks)) { 3380 + /* clear all the session cookies' value */ 3381 + for (int i = 0; i < cookie_cnt; i++) 3382 + emit_store_stack_imm64(&prog, BPF_REG_0, -cookie_off + 8 * i, 0); 3383 + /* clear the return value to make sure fentry always get 0 */ 3384 + emit_store_stack_imm64(&prog, BPF_REG_0, -8, 0); 3385 + } 3386 + 3395 3387 if (fentry->nr_links) { 3396 - if (invoke_bpf(m, &prog, fentry, regs_off, run_ctx_off, 3397 - flags & BPF_TRAMP_F_RET_FENTRY_RET, image, rw_image)) 3388 + if (invoke_bpf(m, &prog, fentry, regs_off, run_ctx_off, func_meta_off, 3389 + flags & BPF_TRAMP_F_RET_FENTRY_RET, image, rw_image, 3390 + func_meta, cookie_off)) 3398 3391 return -EINVAL; 3399 3392 } 3400 3393 ··· 3463 3438 } 3464 3439 } 3465 3440 3441 + /* set the "is_return" flag for fsession */ 3442 + func_meta |= (1ULL << BPF_TRAMP_IS_RETURN_SHIFT); 3443 + if (bpf_fsession_cnt(tlinks)) 3444 + emit_store_stack_imm64(&prog, BPF_REG_0, -func_meta_off, func_meta); 3445 + 3466 3446 if (fexit->nr_links) { 3467 - if (invoke_bpf(m, &prog, fexit, regs_off, run_ctx_off, 3468 - false, image, rw_image)) { 3447 + if (invoke_bpf(m, &prog, fexit, regs_off, run_ctx_off, func_meta_off, 3448 + false, image, rw_image, func_meta, cookie_off)) { 3469 3449 ret = -EINVAL; 3470 3450 goto cleanup; 3471 3451 }
+36
include/linux/bpf.h
··· 1229 1229 #endif 1230 1230 }; 1231 1231 1232 + #define BPF_TRAMP_COOKIE_INDEX_SHIFT 8 1233 + #define BPF_TRAMP_IS_RETURN_SHIFT 63 1234 + 1232 1235 struct bpf_tramp_links { 1233 1236 struct bpf_tramp_link *links[BPF_MAX_TRAMP_LINKS]; 1234 1237 int nr_links; ··· 1312 1309 BPF_TRAMP_MODIFY_RETURN, 1313 1310 BPF_TRAMP_MAX, 1314 1311 BPF_TRAMP_REPLACE, /* more than MAX */ 1312 + BPF_TRAMP_FSESSION, 1315 1313 }; 1316 1314 1317 1315 struct bpf_tramp_image { ··· 1783 1779 enforce_expected_attach_type:1, /* Enforce expected_attach_type checking at attach time */ 1784 1780 call_get_stack:1, /* Do we call bpf_get_stack() or bpf_get_stackid() */ 1785 1781 call_get_func_ip:1, /* Do we call get_func_ip() */ 1782 + call_session_cookie:1, /* Do we call bpf_session_cookie() */ 1786 1783 tstamp_type_access:1, /* Accessed __sk_buff->tstamp_type */ 1787 1784 sleepable:1; /* BPF program is sleepable */ 1788 1785 enum bpf_prog_type type; /* Type of BPF program */ ··· 1878 1873 struct bpf_tramp_link link; 1879 1874 struct bpf_trampoline *trampoline; 1880 1875 struct bpf_prog *tgt_prog; 1876 + }; 1877 + 1878 + struct bpf_fsession_link { 1879 + struct bpf_tracing_link link; 1880 + struct bpf_tramp_link fexit; 1881 1881 }; 1882 1882 1883 1883 struct bpf_raw_tp_link { ··· 2178 2168 } 2179 2169 2180 2170 #endif 2171 + 2172 + static inline int bpf_fsession_cnt(struct bpf_tramp_links *links) 2173 + { 2174 + struct bpf_tramp_links fentries = links[BPF_TRAMP_FENTRY]; 2175 + int cnt = 0; 2176 + 2177 + for (int i = 0; i < links[BPF_TRAMP_FENTRY].nr_links; i++) { 2178 + if (fentries.links[i]->link.prog->expected_attach_type == BPF_TRACE_FSESSION) 2179 + cnt++; 2180 + } 2181 + 2182 + return cnt; 2183 + } 2184 + 2185 + static inline int bpf_fsession_cookie_cnt(struct bpf_tramp_links *links) 2186 + { 2187 + struct bpf_tramp_links fentries = links[BPF_TRAMP_FENTRY]; 2188 + int cnt = 0; 2189 + 2190 + for (int i = 0; i < links[BPF_TRAMP_FENTRY].nr_links; i++) { 2191 + if (fentries.links[i]->link.prog->call_session_cookie) 2192 + cnt++; 2193 + } 2194 + 2195 + return cnt; 2196 + } 2181 2197 2182 2198 int bpf_prog_ctx_arg_info_init(struct bpf_prog *prog, 2183 2199 const struct bpf_ctx_arg_aux *info, u32 cnt);
+1
include/uapi/linux/bpf.h
··· 1145 1145 BPF_NETKIT_PEER, 1146 1146 BPF_TRACE_KPROBE_SESSION, 1147 1147 BPF_TRACE_UPROBE_SESSION, 1148 + BPF_TRACE_FSESSION, 1148 1149 __MAX_BPF_ATTACH_TYPE 1149 1150 }; 1150 1151
+2
kernel/bpf/btf.c
··· 6219 6219 case BPF_TRACE_FENTRY: 6220 6220 case BPF_TRACE_FEXIT: 6221 6221 case BPF_MODIFY_RETURN: 6222 + case BPF_TRACE_FSESSION: 6222 6223 /* allow u64* as ctx */ 6223 6224 if (btf_is_int(t) && t->size == 8) 6224 6225 return 0; ··· 6821 6820 fallthrough; 6822 6821 case BPF_LSM_CGROUP: 6823 6822 case BPF_TRACE_FEXIT: 6823 + case BPF_TRACE_FSESSION: 6824 6824 /* When LSM programs are attached to void LSM hooks 6825 6825 * they use FEXIT trampolines and when attached to 6826 6826 * int LSM hooks, they use MODIFY_RETURN trampolines.
+17 -1
kernel/bpf/syscall.c
··· 3577 3577 case BPF_PROG_TYPE_TRACING: 3578 3578 if (prog->expected_attach_type != BPF_TRACE_FENTRY && 3579 3579 prog->expected_attach_type != BPF_TRACE_FEXIT && 3580 + prog->expected_attach_type != BPF_TRACE_FSESSION && 3580 3581 prog->expected_attach_type != BPF_MODIFY_RETURN) { 3581 3582 err = -EINVAL; 3582 3583 goto out_put_prog; ··· 3627 3626 key = bpf_trampoline_compute_key(tgt_prog, NULL, btf_id); 3628 3627 } 3629 3628 3630 - link = kzalloc(sizeof(*link), GFP_USER); 3629 + if (prog->expected_attach_type == BPF_TRACE_FSESSION) { 3630 + struct bpf_fsession_link *fslink; 3631 + 3632 + fslink = kzalloc(sizeof(*fslink), GFP_USER); 3633 + if (fslink) { 3634 + bpf_link_init(&fslink->fexit.link, BPF_LINK_TYPE_TRACING, 3635 + &bpf_tracing_link_lops, prog, attach_type); 3636 + fslink->fexit.cookie = bpf_cookie; 3637 + link = &fslink->link; 3638 + } else { 3639 + link = NULL; 3640 + } 3641 + } else { 3642 + link = kzalloc(sizeof(*link), GFP_USER); 3643 + } 3631 3644 if (!link) { 3632 3645 err = -ENOMEM; 3633 3646 goto out_put_prog; ··· 4365 4350 case BPF_TRACE_RAW_TP: 4366 4351 case BPF_TRACE_FENTRY: 4367 4352 case BPF_TRACE_FEXIT: 4353 + case BPF_TRACE_FSESSION: 4368 4354 case BPF_MODIFY_RETURN: 4369 4355 return BPF_PROG_TYPE_TRACING; 4370 4356 case BPF_LSM_MAC:
+45 -8
kernel/bpf/trampoline.c
··· 109 109 enum bpf_attach_type eatype = prog->expected_attach_type; 110 110 enum bpf_prog_type ptype = prog->type; 111 111 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 + } 116 123 } 117 124 118 125 void bpf_image_ksym_init(void *data, unsigned int size, struct bpf_ksym *ksym) ··· 566 559 return BPF_TRAMP_MODIFY_RETURN; 567 560 case BPF_TRACE_FEXIT: 568 561 return BPF_TRAMP_FEXIT; 562 + case BPF_TRACE_FSESSION: 563 + return BPF_TRAMP_FSESSION; 569 564 case BPF_LSM_MAC: 570 565 if (!prog->aux->attach_func_proto->type) 571 566 /* The function returns void, we cannot modify its ··· 603 594 struct bpf_trampoline *tr, 604 595 struct bpf_prog *tgt_prog) 605 596 { 597 + struct bpf_fsession_link *fslink = NULL; 606 598 enum bpf_tramp_prog_type kind; 607 599 struct bpf_tramp_link *link_exiting; 600 + struct hlist_head *prog_list; 608 601 int err = 0; 609 602 int cnt = 0, i; 610 603 ··· 632 621 BPF_MOD_JUMP, NULL, 633 622 link->link.prog->bpf_func); 634 623 } 624 + if (kind == BPF_TRAMP_FSESSION) { 625 + prog_list = &tr->progs_hlist[BPF_TRAMP_FENTRY]; 626 + cnt++; 627 + } else { 628 + prog_list = &tr->progs_hlist[kind]; 629 + } 635 630 if (cnt >= BPF_MAX_TRAMP_LINKS) 636 631 return -E2BIG; 637 632 if (!hlist_unhashed(&link->tramp_hlist)) 638 633 /* prog already linked */ 639 634 return -EBUSY; 640 - hlist_for_each_entry(link_exiting, &tr->progs_hlist[kind], tramp_hlist) { 635 + hlist_for_each_entry(link_exiting, prog_list, tramp_hlist) { 641 636 if (link_exiting->link.prog != link->link.prog) 642 637 continue; 643 638 /* prog already linked */ 644 639 return -EBUSY; 645 640 } 646 641 647 - hlist_add_head(&link->tramp_hlist, &tr->progs_hlist[kind]); 648 - tr->progs_cnt[kind]++; 642 + hlist_add_head(&link->tramp_hlist, prog_list); 643 + if (kind == BPF_TRAMP_FSESSION) { 644 + tr->progs_cnt[BPF_TRAMP_FENTRY]++; 645 + fslink = container_of(link, struct bpf_fsession_link, link.link); 646 + hlist_add_head(&fslink->fexit.tramp_hlist, &tr->progs_hlist[BPF_TRAMP_FEXIT]); 647 + tr->progs_cnt[BPF_TRAMP_FEXIT]++; 648 + } else { 649 + tr->progs_cnt[kind]++; 650 + } 649 651 err = bpf_trampoline_update(tr, true /* lock_direct_mutex */); 650 652 if (err) { 651 653 hlist_del_init(&link->tramp_hlist); 652 - tr->progs_cnt[kind]--; 654 + if (kind == BPF_TRAMP_FSESSION) { 655 + tr->progs_cnt[BPF_TRAMP_FENTRY]--; 656 + hlist_del_init(&fslink->fexit.tramp_hlist); 657 + tr->progs_cnt[BPF_TRAMP_FEXIT]--; 658 + } else { 659 + tr->progs_cnt[kind]--; 660 + } 653 661 } 654 662 return err; 655 663 } ··· 702 672 guard(mutex)(&tgt_prog->aux->ext_mutex); 703 673 tgt_prog->aux->is_extended = false; 704 674 return err; 675 + } else if (kind == BPF_TRAMP_FSESSION) { 676 + struct bpf_fsession_link *fslink = 677 + container_of(link, struct bpf_fsession_link, link.link); 678 + 679 + hlist_del_init(&fslink->fexit.tramp_hlist); 680 + tr->progs_cnt[BPF_TRAMP_FEXIT]--; 681 + kind = BPF_TRAMP_FENTRY; 705 682 } 706 683 hlist_del_init(&link->tramp_hlist); 707 684 tr->progs_cnt[kind]--;
+70 -20
kernel/bpf/verifier.c
··· 12484 12484 KF_bpf_arena_alloc_pages, 12485 12485 KF_bpf_arena_free_pages, 12486 12486 KF_bpf_arena_reserve_pages, 12487 + KF_bpf_session_is_return, 12487 12488 }; 12488 12489 12489 12490 BTF_ID_LIST(special_kfunc_list) ··· 12562 12561 BTF_ID(func, bpf_arena_alloc_pages) 12563 12562 BTF_ID(func, bpf_arena_free_pages) 12564 12563 BTF_ID(func, bpf_arena_reserve_pages) 12564 + BTF_ID(func, bpf_session_is_return) 12565 12565 12566 12566 static bool is_task_work_add_kfunc(u32 func_id) 12567 12567 { ··· 12617 12615 struct bpf_reg_state *reg = &regs[regno]; 12618 12616 bool arg_mem_size = false; 12619 12617 12620 - if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) 12618 + if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx] || 12619 + meta->func_id == special_kfunc_list[KF_bpf_session_is_return] || 12620 + meta->func_id == special_kfunc_list[KF_bpf_session_cookie]) 12621 12621 return KF_ARG_PTR_TO_CTX; 12622 12622 12623 12623 if (argno + 1 < nargs && ··· 14405 14401 if (err) 14406 14402 return err; 14407 14403 } 14404 + 14405 + if (meta.func_id == special_kfunc_list[KF_bpf_session_cookie]) 14406 + env->prog->call_session_cookie = true; 14408 14407 14409 14408 return 0; 14410 14409 } ··· 17855 17848 switch (env->prog->expected_attach_type) { 17856 17849 case BPF_TRACE_FENTRY: 17857 17850 case BPF_TRACE_FEXIT: 17851 + case BPF_TRACE_FSESSION: 17858 17852 range = retval_range(0, 0); 17859 17853 break; 17860 17854 case BPF_TRACE_RAW_TP: ··· 23014 23006 desc->func_id == special_kfunc_list[KF_bpf_rdonly_cast]) { 23015 23007 insn_buf[0] = BPF_MOV64_REG(BPF_REG_0, BPF_REG_1); 23016 23008 *cnt = 1; 23009 + } else if (desc->func_id == special_kfunc_list[KF_bpf_session_is_return] && 23010 + env->prog->expected_attach_type == BPF_TRACE_FSESSION) { 23011 + /* 23012 + * inline the bpf_session_is_return() for fsession: 23013 + * bool bpf_session_is_return(void *ctx) 23014 + * { 23015 + * return (((u64 *)ctx)[-1] >> BPF_TRAMP_IS_RETURN_SHIFT) & 1; 23016 + * } 23017 + */ 23018 + insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8); 23019 + insn_buf[1] = BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, BPF_TRAMP_IS_RETURN_SHIFT); 23020 + insn_buf[2] = BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1); 23021 + *cnt = 3; 23022 + } else if (desc->func_id == special_kfunc_list[KF_bpf_session_cookie] && 23023 + env->prog->expected_attach_type == BPF_TRACE_FSESSION) { 23024 + /* 23025 + * inline bpf_session_cookie() for fsession: 23026 + * __u64 *bpf_session_cookie(void *ctx) 23027 + * { 23028 + * u64 off = (((u64 *)ctx)[-1] >> BPF_TRAMP_COOKIE_INDEX_SHIFT) & 0xFF; 23029 + * return &((u64 *)ctx)[-off]; 23030 + * } 23031 + */ 23032 + insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8); 23033 + insn_buf[1] = BPF_ALU64_IMM(BPF_RSH, BPF_REG_0, BPF_TRAMP_COOKIE_INDEX_SHIFT); 23034 + insn_buf[2] = BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xFF); 23035 + insn_buf[3] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, 3); 23036 + insn_buf[4] = BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1); 23037 + insn_buf[5] = BPF_ALU64_IMM(BPF_NEG, BPF_REG_0, 0); 23038 + *cnt = 6; 23017 23039 } 23018 23040 23019 23041 if (env->insn_aux_data[insn_idx].arg_prog) { ··· 23784 23746 23785 23747 /* skip 'void *__data' in btf_trace_##name() and save to reg0 */ 23786 23748 insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, nr_args - 1); 23749 + cnt = 1; 23787 23750 } else { 23788 23751 /* Load nr_args from ctx - 8 */ 23789 23752 insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8); 23753 + insn_buf[1] = BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xFF); 23754 + cnt = 2; 23790 23755 } 23791 - insn_buf[1] = BPF_JMP32_REG(BPF_JGE, BPF_REG_2, BPF_REG_0, 6); 23792 - insn_buf[2] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 3); 23793 - insn_buf[3] = BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_1); 23794 - insn_buf[4] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 0); 23795 - insn_buf[5] = BPF_STX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0); 23796 - insn_buf[6] = BPF_MOV64_IMM(BPF_REG_0, 0); 23797 - insn_buf[7] = BPF_JMP_A(1); 23798 - insn_buf[8] = BPF_MOV64_IMM(BPF_REG_0, -EINVAL); 23799 - cnt = 9; 23756 + insn_buf[cnt++] = BPF_JMP32_REG(BPF_JGE, BPF_REG_2, BPF_REG_0, 6); 23757 + insn_buf[cnt++] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_2, 3); 23758 + insn_buf[cnt++] = BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_1); 23759 + insn_buf[cnt++] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 0); 23760 + insn_buf[cnt++] = BPF_STX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0); 23761 + insn_buf[cnt++] = BPF_MOV64_IMM(BPF_REG_0, 0); 23762 + insn_buf[cnt++] = BPF_JMP_A(1); 23763 + insn_buf[cnt++] = BPF_MOV64_IMM(BPF_REG_0, -EINVAL); 23800 23764 23801 23765 new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt); 23802 23766 if (!new_prog) ··· 23814 23774 if (prog_type == BPF_PROG_TYPE_TRACING && 23815 23775 insn->imm == BPF_FUNC_get_func_ret) { 23816 23776 if (eatype == BPF_TRACE_FEXIT || 23777 + eatype == BPF_TRACE_FSESSION || 23817 23778 eatype == BPF_MODIFY_RETURN) { 23818 23779 /* Load nr_args from ctx - 8 */ 23819 23780 insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8); 23820 - insn_buf[1] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, 3); 23821 - insn_buf[2] = BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1); 23822 - insn_buf[3] = BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0); 23823 - insn_buf[4] = BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, 0); 23824 - insn_buf[5] = BPF_MOV64_IMM(BPF_REG_0, 0); 23825 - cnt = 6; 23781 + insn_buf[1] = BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xFF); 23782 + insn_buf[2] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, 3); 23783 + insn_buf[3] = BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1); 23784 + insn_buf[4] = BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0); 23785 + insn_buf[5] = BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, 0); 23786 + insn_buf[6] = BPF_MOV64_IMM(BPF_REG_0, 0); 23787 + cnt = 7; 23826 23788 } else { 23827 23789 insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, -EOPNOTSUPP); 23828 23790 cnt = 1; ··· 23848 23806 23849 23807 /* skip 'void *__data' in btf_trace_##name() and save to reg0 */ 23850 23808 insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, nr_args - 1); 23809 + cnt = 1; 23851 23810 } else { 23852 23811 /* Load nr_args from ctx - 8 */ 23853 23812 insn_buf[0] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, -8); 23813 + insn_buf[1] = BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xFF); 23814 + cnt = 2; 23854 23815 } 23855 23816 23856 - new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, 1); 23817 + new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt); 23857 23818 if (!new_prog) 23858 23819 return -ENOMEM; 23859 23820 23821 + delta += cnt - 1; 23860 23822 env->prog = prog = new_prog; 23861 23823 insn = new_prog->insnsi + i + delta; 23862 23824 goto next_insn; ··· 24771 24725 if (tgt_prog->type == BPF_PROG_TYPE_TRACING && 24772 24726 prog_extension && 24773 24727 (tgt_prog->expected_attach_type == BPF_TRACE_FENTRY || 24774 - tgt_prog->expected_attach_type == BPF_TRACE_FEXIT)) { 24728 + tgt_prog->expected_attach_type == BPF_TRACE_FEXIT || 24729 + tgt_prog->expected_attach_type == BPF_TRACE_FSESSION)) { 24775 24730 /* Program extensions can extend all program types 24776 24731 * except fentry/fexit. The reason is the following. 24777 24732 * The fentry/fexit programs are used for performance ··· 24787 24740 * beyond reasonable stack size. Hence extending fentry 24788 24741 * is not allowed. 24789 24742 */ 24790 - bpf_log(log, "Cannot extend fentry/fexit\n"); 24743 + bpf_log(log, "Cannot extend fentry/fexit/fsession\n"); 24791 24744 return -EINVAL; 24792 24745 } 24793 24746 } else { ··· 24871 24824 case BPF_LSM_CGROUP: 24872 24825 case BPF_TRACE_FENTRY: 24873 24826 case BPF_TRACE_FEXIT: 24827 + case BPF_TRACE_FSESSION: 24874 24828 if (!btf_type_is_func(t)) { 24875 24829 bpf_log(log, "attach_btf_id %u is not a function\n", 24876 24830 btf_id); ··· 25038 24990 case BPF_TRACE_FEXIT: 25039 24991 case BPF_MODIFY_RETURN: 25040 24992 case BPF_TRACE_ITER: 24993 + case BPF_TRACE_FSESSION: 25041 24994 return true; 25042 24995 default: 25043 24996 return false; ··· 25120 25071 tgt_info.tgt_name); 25121 25072 return -EINVAL; 25122 25073 } else if ((prog->expected_attach_type == BPF_TRACE_FEXIT || 25074 + prog->expected_attach_type == BPF_TRACE_FSESSION || 25123 25075 prog->expected_attach_type == BPF_MODIFY_RETURN) && 25124 25076 btf_id_set_contains(&noreturn_deny, btf_id)) { 25125 - verbose(env, "Attaching fexit/fmod_ret to __noreturn function '%s' is rejected.\n", 25077 + verbose(env, "Attaching fexit/fsession/fmod_ret to __noreturn function '%s' is rejected.\n", 25126 25078 tgt_info.tgt_name); 25127 25079 return -EINVAL; 25128 25080 }
+31 -18
kernel/trace/bpf_trace.c
··· 1194 1194 BPF_CALL_3(get_func_arg, void *, ctx, u32, n, u64 *, value) 1195 1195 { 1196 1196 /* This helper call is inlined by verifier. */ 1197 - u64 nr_args = ((u64 *)ctx)[-1]; 1197 + u64 nr_args = ((u64 *)ctx)[-1] & 0xFF; 1198 1198 1199 1199 if ((u64) n >= nr_args) 1200 1200 return -EINVAL; ··· 1214 1214 BPF_CALL_2(get_func_ret, void *, ctx, u64 *, value) 1215 1215 { 1216 1216 /* This helper call is inlined by verifier. */ 1217 - u64 nr_args = ((u64 *)ctx)[-1]; 1217 + u64 nr_args = ((u64 *)ctx)[-1] & 0xFF; 1218 1218 1219 1219 *value = ((u64 *)ctx)[nr_args]; 1220 1220 return 0; ··· 1231 1231 BPF_CALL_1(get_func_arg_cnt, void *, ctx) 1232 1232 { 1233 1233 /* This helper call is inlined by verifier. */ 1234 - return ((u64 *)ctx)[-1]; 1234 + return ((u64 *)ctx)[-1] & 0xFF; 1235 1235 } 1236 1236 1237 1237 static const struct bpf_func_proto bpf_get_func_arg_cnt_proto = { ··· 1286 1286 1287 1287 static inline bool is_kprobe_session(const struct bpf_prog *prog) 1288 1288 { 1289 - return prog->expected_attach_type == BPF_TRACE_KPROBE_SESSION; 1289 + return prog->type == BPF_PROG_TYPE_KPROBE && 1290 + prog->expected_attach_type == BPF_TRACE_KPROBE_SESSION; 1290 1291 } 1291 1292 1292 1293 static inline bool is_uprobe_multi(const struct bpf_prog *prog) ··· 1298 1297 1299 1298 static inline bool is_uprobe_session(const struct bpf_prog *prog) 1300 1299 { 1301 - return prog->expected_attach_type == BPF_TRACE_UPROBE_SESSION; 1300 + return prog->type == BPF_PROG_TYPE_KPROBE && 1301 + prog->expected_attach_type == BPF_TRACE_UPROBE_SESSION; 1302 + } 1303 + 1304 + static inline bool is_trace_fsession(const struct bpf_prog *prog) 1305 + { 1306 + return prog->type == BPF_PROG_TYPE_TRACING && 1307 + prog->expected_attach_type == BPF_TRACE_FSESSION; 1302 1308 } 1303 1309 1304 1310 static const struct bpf_func_proto * ··· 3331 3323 3332 3324 __bpf_kfunc_start_defs(); 3333 3325 3334 - __bpf_kfunc bool bpf_session_is_return(void) 3326 + __bpf_kfunc bool bpf_session_is_return(void *ctx) 3335 3327 { 3336 3328 struct bpf_session_run_ctx *session_ctx; 3337 3329 ··· 3339 3331 return session_ctx->is_return; 3340 3332 } 3341 3333 3342 - __bpf_kfunc __u64 *bpf_session_cookie(void) 3334 + __bpf_kfunc __u64 *bpf_session_cookie(void *ctx) 3343 3335 { 3344 3336 struct bpf_session_run_ctx *session_ctx; 3345 3337 ··· 3349 3341 3350 3342 __bpf_kfunc_end_defs(); 3351 3343 3352 - BTF_KFUNCS_START(kprobe_multi_kfunc_set_ids) 3344 + BTF_KFUNCS_START(session_kfunc_set_ids) 3353 3345 BTF_ID_FLAGS(func, bpf_session_is_return) 3354 3346 BTF_ID_FLAGS(func, bpf_session_cookie) 3355 - BTF_KFUNCS_END(kprobe_multi_kfunc_set_ids) 3347 + BTF_KFUNCS_END(session_kfunc_set_ids) 3356 3348 3357 - static int bpf_kprobe_multi_filter(const struct bpf_prog *prog, u32 kfunc_id) 3349 + static int bpf_session_filter(const struct bpf_prog *prog, u32 kfunc_id) 3358 3350 { 3359 - if (!btf_id_set8_contains(&kprobe_multi_kfunc_set_ids, kfunc_id)) 3351 + if (!btf_id_set8_contains(&session_kfunc_set_ids, kfunc_id)) 3360 3352 return 0; 3361 3353 3362 - if (!is_kprobe_session(prog) && !is_uprobe_session(prog)) 3354 + if (!is_kprobe_session(prog) && !is_uprobe_session(prog) && !is_trace_fsession(prog)) 3363 3355 return -EACCES; 3364 3356 3365 3357 return 0; 3366 3358 } 3367 3359 3368 - static const struct btf_kfunc_id_set bpf_kprobe_multi_kfunc_set = { 3360 + static const struct btf_kfunc_id_set bpf_session_kfunc_set = { 3369 3361 .owner = THIS_MODULE, 3370 - .set = &kprobe_multi_kfunc_set_ids, 3371 - .filter = bpf_kprobe_multi_filter, 3362 + .set = &session_kfunc_set_ids, 3363 + .filter = bpf_session_filter, 3372 3364 }; 3373 3365 3374 - static int __init bpf_kprobe_multi_kfuncs_init(void) 3366 + static int __init bpf_trace_kfuncs_init(void) 3375 3367 { 3376 - return register_btf_kfunc_id_set(BPF_PROG_TYPE_KPROBE, &bpf_kprobe_multi_kfunc_set); 3368 + int err = 0; 3369 + 3370 + err = err ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_KPROBE, &bpf_session_kfunc_set); 3371 + err = err ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_session_kfunc_set); 3372 + 3373 + return err; 3377 3374 } 3378 3375 3379 - late_initcall(bpf_kprobe_multi_kfuncs_init); 3376 + late_initcall(bpf_trace_kfuncs_init); 3380 3377 3381 3378 typedef int (*copy_fn_t)(void *dst, const void *src, u32 size, struct task_struct *tsk); 3382 3379
+1
net/bpf/test_run.c
··· 685 685 switch (prog->expected_attach_type) { 686 686 case BPF_TRACE_FENTRY: 687 687 case BPF_TRACE_FEXIT: 688 + case BPF_TRACE_FSESSION: 688 689 if (bpf_fentry_test1(1) != 2 || 689 690 bpf_fentry_test2(2, 3) != 5 || 690 691 bpf_fentry_test3(4, 5, 6) != 15 ||
+1
net/core/bpf_sk_storage.c
··· 365 365 return true; 366 366 case BPF_TRACE_FENTRY: 367 367 case BPF_TRACE_FEXIT: 368 + case BPF_TRACE_FSESSION: 368 369 return !!strncmp(prog->aux->attach_func_name, "bpf_sk_storage", 369 370 strlen("bpf_sk_storage")); 370 371 default:
+1
tools/bpf/bpftool/common.c
··· 1191 1191 case BPF_TRACE_FENTRY: return "fentry"; 1192 1192 case BPF_TRACE_FEXIT: return "fexit"; 1193 1193 case BPF_MODIFY_RETURN: return "mod_ret"; 1194 + case BPF_TRACE_FSESSION: return "fsession"; 1194 1195 case BPF_SK_REUSEPORT_SELECT: return "sk_skb_reuseport_select"; 1195 1196 case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE: return "sk_skb_reuseport_select_or_migrate"; 1196 1197 default: return libbpf_bpf_attach_type_str(t);
+1
tools/include/uapi/linux/bpf.h
··· 1145 1145 BPF_NETKIT_PEER, 1146 1146 BPF_TRACE_KPROBE_SESSION, 1147 1147 BPF_TRACE_UPROBE_SESSION, 1148 + BPF_TRACE_FSESSION, 1148 1149 __MAX_BPF_ATTACH_TYPE 1149 1150 }; 1150 1151
+1
tools/lib/bpf/bpf.c
··· 794 794 case BPF_TRACE_FENTRY: 795 795 case BPF_TRACE_FEXIT: 796 796 case BPF_MODIFY_RETURN: 797 + case BPF_TRACE_FSESSION: 797 798 case BPF_LSM_MAC: 798 799 attr.link_create.tracing.cookie = OPTS_GET(opts, tracing.cookie, 0); 799 800 if (!OPTS_ZEROED(opts, tracing))
+3
tools/lib/bpf/libbpf.c
··· 115 115 [BPF_TRACE_FENTRY] = "trace_fentry", 116 116 [BPF_TRACE_FEXIT] = "trace_fexit", 117 117 [BPF_MODIFY_RETURN] = "modify_return", 118 + [BPF_TRACE_FSESSION] = "trace_fsession", 118 119 [BPF_LSM_MAC] = "lsm_mac", 119 120 [BPF_LSM_CGROUP] = "lsm_cgroup", 120 121 [BPF_SK_LOOKUP] = "sk_lookup", ··· 9860 9859 SEC_DEF("fentry.s+", TRACING, BPF_TRACE_FENTRY, SEC_ATTACH_BTF | SEC_SLEEPABLE, attach_trace), 9861 9860 SEC_DEF("fmod_ret.s+", TRACING, BPF_MODIFY_RETURN, SEC_ATTACH_BTF | SEC_SLEEPABLE, attach_trace), 9862 9861 SEC_DEF("fexit.s+", TRACING, BPF_TRACE_FEXIT, SEC_ATTACH_BTF | SEC_SLEEPABLE, attach_trace), 9862 + SEC_DEF("fsession+", TRACING, BPF_TRACE_FSESSION, SEC_ATTACH_BTF, attach_trace), 9863 + SEC_DEF("fsession.s+", TRACING, BPF_TRACE_FSESSION, SEC_ATTACH_BTF | SEC_SLEEPABLE, attach_trace), 9863 9864 SEC_DEF("freplace+", EXT, 0, SEC_ATTACH_BTF, attach_trace), 9864 9865 SEC_DEF("lsm+", LSM, BPF_LSM_MAC, SEC_ATTACH_BTF, attach_lsm), 9865 9866 SEC_DEF("lsm.s+", LSM, BPF_LSM_MAC, SEC_ATTACH_BTF | SEC_SLEEPABLE, attach_lsm),
-3
tools/testing/selftests/bpf/bpf_kfuncs.h
··· 79 79 struct bpf_dynptr *sig_ptr, 80 80 struct bpf_key *trusted_keyring) __ksym; 81 81 82 - extern bool bpf_session_is_return(void) __ksym __weak; 83 - extern __u64 *bpf_session_cookie(void) __ksym __weak; 84 - 85 82 struct dentry; 86 83 /* Description 87 84 * Returns xattr of a dentry
+124
tools/testing/selftests/bpf/prog_tests/fsession_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2025 ChinaTelecom */ 3 + #include <test_progs.h> 4 + #include "fsession_test.skel.h" 5 + 6 + static int check_result(struct fsession_test *skel) 7 + { 8 + LIBBPF_OPTS(bpf_test_run_opts, topts); 9 + int err, prog_fd; 10 + 11 + /* Trigger test function calls */ 12 + prog_fd = bpf_program__fd(skel->progs.test1); 13 + err = bpf_prog_test_run_opts(prog_fd, &topts); 14 + if (!ASSERT_OK(err, "test_run_opts err")) 15 + return err; 16 + if (!ASSERT_OK(topts.retval, "test_run_opts retval")) 17 + return topts.retval; 18 + 19 + for (int i = 0; i < sizeof(*skel->bss) / sizeof(__u64); i++) { 20 + if (!ASSERT_EQ(((__u64 *)skel->bss)[i], 1, "test_result")) 21 + return -EINVAL; 22 + } 23 + 24 + return 0; 25 + } 26 + 27 + static void test_fsession_basic(void) 28 + { 29 + struct fsession_test *skel = NULL; 30 + int err; 31 + 32 + skel = fsession_test__open_and_load(); 33 + if (!ASSERT_OK_PTR(skel, "fsession_test__open_and_load")) 34 + goto cleanup; 35 + 36 + err = fsession_test__attach(skel); 37 + if (!ASSERT_OK(err, "fsession_attach")) 38 + goto cleanup; 39 + 40 + check_result(skel); 41 + cleanup: 42 + fsession_test__destroy(skel); 43 + } 44 + 45 + static void test_fsession_reattach(void) 46 + { 47 + struct fsession_test *skel = NULL; 48 + int err; 49 + 50 + skel = fsession_test__open_and_load(); 51 + if (!ASSERT_OK_PTR(skel, "fsession_test__open_and_load")) 52 + goto cleanup; 53 + 54 + /* first attach */ 55 + err = fsession_test__attach(skel); 56 + if (!ASSERT_OK(err, "fsession_first_attach")) 57 + goto cleanup; 58 + 59 + if (check_result(skel)) 60 + goto cleanup; 61 + 62 + /* detach */ 63 + fsession_test__detach(skel); 64 + 65 + /* reset counters */ 66 + memset(skel->bss, 0, sizeof(*skel->bss)); 67 + 68 + /* second attach */ 69 + err = fsession_test__attach(skel); 70 + if (!ASSERT_OK(err, "fsession_second_attach")) 71 + goto cleanup; 72 + 73 + if (check_result(skel)) 74 + goto cleanup; 75 + 76 + cleanup: 77 + fsession_test__destroy(skel); 78 + } 79 + 80 + static void test_fsession_cookie(void) 81 + { 82 + struct fsession_test *skel = NULL; 83 + int err; 84 + 85 + skel = fsession_test__open(); 86 + if (!ASSERT_OK_PTR(skel, "fsession_test__open")) 87 + goto cleanup; 88 + 89 + /* 90 + * The test_fsession_basic() will test the session cookie with 91 + * bpf_get_func_ip() case, so we need only check 92 + * the cookie without bpf_get_func_ip() case here 93 + */ 94 + bpf_program__set_autoload(skel->progs.test6, false); 95 + 96 + err = fsession_test__load(skel); 97 + if (!ASSERT_OK(err, "fsession_test__load")) 98 + goto cleanup; 99 + 100 + err = fsession_test__attach(skel); 101 + if (!ASSERT_OK(err, "fsession_attach")) 102 + goto cleanup; 103 + 104 + skel->bss->test6_entry_result = 1; 105 + skel->bss->test6_exit_result = 1; 106 + 107 + check_result(skel); 108 + cleanup: 109 + fsession_test__destroy(skel); 110 + } 111 + 112 + void test_fsession_test(void) 113 + { 114 + #if !defined(__x86_64__) 115 + test__skip(); 116 + return; 117 + #endif 118 + if (test__start_subtest("fsession_test")) 119 + test_fsession_basic(); 120 + if (test__start_subtest("fsession_reattach")) 121 + test_fsession_reattach(); 122 + if (test__start_subtest("fsession_cookie")) 123 + test_fsession_cookie(); 124 + }
+1
tools/testing/selftests/bpf/prog_tests/get_func_args_test.c
··· 41 41 ASSERT_EQ(skel->bss->test4_result, 1, "test4_result"); 42 42 ASSERT_EQ(skel->bss->test5_result, 1, "test5_result"); 43 43 ASSERT_EQ(skel->bss->test6_result, 1, "test6_result"); 44 + ASSERT_EQ(skel->bss->test7_result, 1, "test7_result"); 44 45 45 46 cleanup: 46 47 get_func_args_test__destroy(skel);
+2
tools/testing/selftests/bpf/prog_tests/get_func_ip_test.c
··· 46 46 ASSERT_EQ(skel->bss->test5_result, 1, "test5_result"); 47 47 ASSERT_EQ(skel->bss->test7_result, 1, "test7_result"); 48 48 ASSERT_EQ(skel->bss->test8_result, 1, "test8_result"); 49 + ASSERT_EQ(skel->bss->test9_entry_result, 1, "test9_entry_result"); 50 + ASSERT_EQ(skel->bss->test9_exit_result, 1, "test9_exit_result"); 49 51 50 52 cleanup: 51 53 get_func_ip_test__destroy(skel);
+1 -1
tools/testing/selftests/bpf/prog_tests/tracing_failure.c
··· 73 73 static void test_fexit_noreturns(void) 74 74 { 75 75 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."); 77 77 } 78 78 79 79 void test_tracing_failure(void)
+179
tools/testing/selftests/bpf/progs/fsession_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2025 ChinaTelecom */ 3 + #include <vmlinux.h> 4 + #include <bpf/bpf_helpers.h> 5 + #include <bpf/bpf_tracing.h> 6 + 7 + char _license[] SEC("license") = "GPL"; 8 + 9 + __u64 test1_entry_result = 0; 10 + __u64 test1_exit_result = 0; 11 + 12 + SEC("fsession/bpf_fentry_test1") 13 + int BPF_PROG(test1, int a, int ret) 14 + { 15 + bool is_exit = bpf_session_is_return(ctx); 16 + 17 + if (!is_exit) { 18 + test1_entry_result = a == 1 && ret == 0; 19 + return 0; 20 + } 21 + 22 + test1_exit_result = a == 1 && ret == 2; 23 + return 0; 24 + } 25 + 26 + __u64 test2_entry_result = 0; 27 + __u64 test2_exit_result = 0; 28 + 29 + SEC("fsession/bpf_fentry_test3") 30 + int BPF_PROG(test2, char a, int b, __u64 c, int ret) 31 + { 32 + bool is_exit = bpf_session_is_return(ctx); 33 + 34 + if (!is_exit) { 35 + test2_entry_result = a == 4 && b == 5 && c == 6 && ret == 0; 36 + return 0; 37 + } 38 + 39 + test2_exit_result = a == 4 && b == 5 && c == 6 && ret == 15; 40 + return 0; 41 + } 42 + 43 + __u64 test3_entry_result = 0; 44 + __u64 test3_exit_result = 0; 45 + 46 + SEC("fsession/bpf_fentry_test4") 47 + int BPF_PROG(test3, void *a, char b, int c, __u64 d, int ret) 48 + { 49 + bool is_exit = bpf_session_is_return(ctx); 50 + 51 + if (!is_exit) { 52 + test3_entry_result = a == (void *)7 && b == 8 && c == 9 && d == 10 && ret == 0; 53 + return 0; 54 + } 55 + 56 + test3_exit_result = a == (void *)7 && b == 8 && c == 9 && d == 10 && ret == 34; 57 + return 0; 58 + } 59 + 60 + __u64 test4_entry_result = 0; 61 + __u64 test4_exit_result = 0; 62 + 63 + SEC("fsession/bpf_fentry_test5") 64 + int BPF_PROG(test4, __u64 a, void *b, short c, int d, __u64 e, int ret) 65 + { 66 + bool is_exit = bpf_session_is_return(ctx); 67 + 68 + if (!is_exit) { 69 + test4_entry_result = a == 11 && b == (void *)12 && c == 13 && d == 14 && 70 + e == 15 && ret == 0; 71 + return 0; 72 + } 73 + 74 + test4_exit_result = a == 11 && b == (void *)12 && c == 13 && d == 14 && 75 + e == 15 && ret == 65; 76 + return 0; 77 + } 78 + 79 + __u64 test5_entry_result = 0; 80 + __u64 test5_exit_result = 0; 81 + 82 + SEC("fsession/bpf_fentry_test7") 83 + int BPF_PROG(test5, struct bpf_fentry_test_t *arg, int ret) 84 + { 85 + bool is_exit = bpf_session_is_return(ctx); 86 + 87 + if (!is_exit) { 88 + if (!arg) 89 + test5_entry_result = ret == 0; 90 + return 0; 91 + } 92 + 93 + if (!arg) 94 + test5_exit_result = 1; 95 + return 0; 96 + } 97 + 98 + __u64 test6_entry_result = 0; 99 + __u64 test6_exit_result = 0; 100 + SEC("fsession/bpf_fentry_test1") 101 + int BPF_PROG(test6, int a) 102 + { 103 + __u64 addr = bpf_get_func_ip(ctx); 104 + 105 + if (bpf_session_is_return(ctx)) 106 + test6_exit_result = (const void *) addr == &bpf_fentry_test1; 107 + else 108 + test6_entry_result = (const void *) addr == &bpf_fentry_test1; 109 + return 0; 110 + } 111 + 112 + __u64 test7_entry_ok = 0; 113 + __u64 test7_exit_ok = 0; 114 + SEC("fsession/bpf_fentry_test1") 115 + int BPF_PROG(test7, int a) 116 + { 117 + volatile __u64 *cookie = bpf_session_cookie(ctx); 118 + 119 + if (!bpf_session_is_return(ctx)) { 120 + *cookie = 0xAAAABBBBCCCCDDDDull; 121 + test7_entry_ok = *cookie == 0xAAAABBBBCCCCDDDDull; 122 + return 0; 123 + } 124 + 125 + test7_exit_ok = *cookie == 0xAAAABBBBCCCCDDDDull; 126 + return 0; 127 + } 128 + 129 + __u64 test8_entry_ok = 0; 130 + __u64 test8_exit_ok = 0; 131 + 132 + SEC("fsession/bpf_fentry_test1") 133 + int BPF_PROG(test8, int a) 134 + { 135 + volatile __u64 *cookie = bpf_session_cookie(ctx); 136 + 137 + if (!bpf_session_is_return(ctx)) { 138 + *cookie = 0x1111222233334444ull; 139 + test8_entry_ok = *cookie == 0x1111222233334444ull; 140 + return 0; 141 + } 142 + 143 + test8_exit_ok = *cookie == 0x1111222233334444ull; 144 + return 0; 145 + } 146 + 147 + __u64 test9_entry_result = 0; 148 + __u64 test9_exit_result = 0; 149 + 150 + SEC("fsession/bpf_fentry_test1") 151 + int BPF_PROG(test9, int a, int ret) 152 + { 153 + __u64 *cookie = bpf_session_cookie(ctx); 154 + 155 + if (!bpf_session_is_return(ctx)) { 156 + test9_entry_result = a == 1 && ret == 0; 157 + *cookie = 0x123456ULL; 158 + return 0; 159 + } 160 + 161 + test9_exit_result = a == 1 && ret == 2 && *cookie == 0x123456ULL; 162 + return 0; 163 + } 164 + 165 + __u64 test10_result = 0; 166 + SEC("fexit/bpf_fentry_test1") 167 + int BPF_PROG(test10, int a, int ret) 168 + { 169 + test10_result = a == 1 && ret == 2; 170 + return 0; 171 + } 172 + 173 + __u64 test11_result = 0; 174 + SEC("fentry/bpf_fentry_test1") 175 + int BPF_PROG(test11, int a) 176 + { 177 + test11_result = a == 1; 178 + return 0; 179 + }
+39 -1
tools/testing/selftests/bpf/progs/get_func_args_test.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 - #include <linux/bpf.h> 2 + #include <vmlinux.h> 3 3 #include <bpf/bpf_helpers.h> 4 4 #include <bpf/bpf_tracing.h> 5 5 #include <errno.h> ··· 165 165 166 166 return 0; 167 167 } 168 + 169 + __u64 test7_result = 0; 170 + #ifdef __TARGET_ARCH_x86 171 + SEC("fsession/bpf_fentry_test1") 172 + int BPF_PROG(test7) 173 + { 174 + __u64 cnt = bpf_get_func_arg_cnt(ctx); 175 + __u64 a = 0, z = 0, ret = 0; 176 + __s64 err; 177 + 178 + test7_result = cnt == 1; 179 + 180 + /* valid arguments */ 181 + err = bpf_get_func_arg(ctx, 0, &a); 182 + test7_result &= err == 0 && ((int) a == 1); 183 + 184 + /* not valid argument */ 185 + err = bpf_get_func_arg(ctx, 1, &z); 186 + test7_result &= err == -EINVAL; 187 + 188 + if (bpf_session_is_return(ctx)) { 189 + err = bpf_get_func_ret(ctx, &ret); 190 + test7_result &= err == 0 && ret == 2; 191 + } else { 192 + err = bpf_get_func_ret(ctx, &ret); 193 + test7_result &= err == 0 && ret == 0; 194 + } 195 + 196 + return 0; 197 + } 198 + #else 199 + SEC("fentry/bpf_fentry_test1") 200 + int BPF_PROG(test7) 201 + { 202 + test7_result = 1; 203 + return 0; 204 + } 205 + #endif
+23
tools/testing/selftests/bpf/progs/get_func_ip_test.c
··· 103 103 test8_result = (const void *) addr == (const void *) uprobe_trigger; 104 104 return 0; 105 105 } 106 + 107 + __u64 test9_entry_result = 0; 108 + __u64 test9_exit_result = 0; 109 + #ifdef __TARGET_ARCH_x86 110 + SEC("fsession/bpf_fentry_test1") 111 + int BPF_PROG(test9, int a) 112 + { 113 + __u64 addr = bpf_get_func_ip(ctx); 114 + 115 + if (bpf_session_is_return(ctx)) 116 + test9_exit_result = (const void *) addr == &bpf_fentry_test1; 117 + else 118 + test9_entry_result = (const void *) addr == &bpf_fentry_test1; 119 + return 0; 120 + } 121 + #else 122 + SEC("fentry/bpf_fentry_test1") 123 + int BPF_PROG(test9, int a) 124 + { 125 + test9_entry_result = test9_exit_result = 1; 126 + return 0; 127 + } 128 + #endif
+7 -8
tools/testing/selftests/bpf/progs/kprobe_multi_session_cookie.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 - #include <linux/bpf.h> 2 + #include <vmlinux.h> 3 3 #include <bpf/bpf_helpers.h> 4 4 #include <bpf/bpf_tracing.h> 5 5 #include <stdbool.h> 6 - #include "bpf_kfuncs.h" 7 6 8 7 char _license[] SEC("license") = "GPL"; 9 8 ··· 22 23 return 0; 23 24 } 24 25 25 - static int check_cookie(__u64 val, __u64 *result) 26 + static int check_cookie(struct pt_regs *ctx, __u64 val, __u64 *result) 26 27 { 27 28 __u64 *cookie; 28 29 29 30 if (bpf_get_current_pid_tgid() >> 32 != pid) 30 31 return 1; 31 32 32 - cookie = bpf_session_cookie(); 33 + cookie = bpf_session_cookie(ctx); 33 34 34 - if (bpf_session_is_return()) 35 + if (bpf_session_is_return(ctx)) 35 36 *result = *cookie == val ? val : 0; 36 37 else 37 38 *cookie = val; ··· 41 42 SEC("kprobe.session/bpf_fentry_test1") 42 43 int test_kprobe_1(struct pt_regs *ctx) 43 44 { 44 - return check_cookie(1, &test_kprobe_1_result); 45 + return check_cookie(ctx, 1, &test_kprobe_1_result); 45 46 } 46 47 47 48 SEC("kprobe.session/bpf_fentry_test1") 48 49 int test_kprobe_2(struct pt_regs *ctx) 49 50 { 50 - return check_cookie(2, &test_kprobe_2_result); 51 + return check_cookie(ctx, 2, &test_kprobe_2_result); 51 52 } 52 53 53 54 SEC("kprobe.session/bpf_fentry_test1") 54 55 int test_kprobe_3(struct pt_regs *ctx) 55 56 { 56 - return check_cookie(3, &test_kprobe_3_result); 57 + return check_cookie(ctx, 3, &test_kprobe_3_result); 57 58 }
+3 -4
tools/testing/selftests/bpf/progs/uprobe_multi_session.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 - #include <linux/bpf.h> 2 + #include <vmlinux.h> 3 3 #include <bpf/bpf_helpers.h> 4 4 #include <bpf/bpf_tracing.h> 5 5 #include <stdbool.h> 6 - #include "bpf_kfuncs.h" 7 6 #include "bpf_misc.h" 8 7 9 8 char _license[] SEC("license") = "GPL"; ··· 50 51 SEC("uprobe.session//proc/self/exe:uprobe_multi_func_*") 51 52 int uprobe(struct pt_regs *ctx) 52 53 { 53 - return uprobe_multi_check(ctx, bpf_session_is_return()); 54 + return uprobe_multi_check(ctx, bpf_session_is_return(ctx)); 54 55 } 55 56 56 57 static __always_inline bool verify_sleepable_user_copy(void) ··· 66 67 { 67 68 if (verify_sleepable_user_copy()) 68 69 uprobe_multi_sleep_result++; 69 - return uprobe_multi_check(ctx, bpf_session_is_return()); 70 + return uprobe_multi_check(ctx, bpf_session_is_return(ctx)); 70 71 }
+7 -8
tools/testing/selftests/bpf/progs/uprobe_multi_session_cookie.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 - #include <linux/bpf.h> 2 + #include <vmlinux.h> 3 3 #include <bpf/bpf_helpers.h> 4 4 #include <bpf/bpf_tracing.h> 5 5 #include <stdbool.h> 6 - #include "bpf_kfuncs.h" 7 6 8 7 char _license[] SEC("license") = "GPL"; 9 8 ··· 12 13 __u64 test_uprobe_2_result = 0; 13 14 __u64 test_uprobe_3_result = 0; 14 15 15 - static int check_cookie(__u64 val, __u64 *result) 16 + static int check_cookie(struct pt_regs *ctx, __u64 val, __u64 *result) 16 17 { 17 18 __u64 *cookie; 18 19 19 20 if (bpf_get_current_pid_tgid() >> 32 != pid) 20 21 return 1; 21 22 22 - cookie = bpf_session_cookie(); 23 + cookie = bpf_session_cookie(ctx); 23 24 24 - if (bpf_session_is_return()) 25 + if (bpf_session_is_return(ctx)) 25 26 *result = *cookie == val ? val : 0; 26 27 else 27 28 *cookie = val; ··· 31 32 SEC("uprobe.session//proc/self/exe:uprobe_multi_func_1") 32 33 int uprobe_1(struct pt_regs *ctx) 33 34 { 34 - return check_cookie(1, &test_uprobe_1_result); 35 + return check_cookie(ctx, 1, &test_uprobe_1_result); 35 36 } 36 37 37 38 SEC("uprobe.session//proc/self/exe:uprobe_multi_func_2") 38 39 int uprobe_2(struct pt_regs *ctx) 39 40 { 40 - return check_cookie(2, &test_uprobe_2_result); 41 + return check_cookie(ctx, 2, &test_uprobe_2_result); 41 42 } 42 43 43 44 SEC("uprobe.session//proc/self/exe:uprobe_multi_func_3") 44 45 int uprobe_3(struct pt_regs *ctx) 45 46 { 46 - return check_cookie(3, &test_uprobe_3_result); 47 + return check_cookie(ctx, 3, &test_uprobe_3_result); 47 48 }
+5 -6
tools/testing/selftests/bpf/progs/uprobe_multi_session_recursive.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 - #include <linux/bpf.h> 2 + #include <vmlinux.h> 3 3 #include <bpf/bpf_helpers.h> 4 4 #include <bpf/bpf_tracing.h> 5 5 #include <stdbool.h> 6 - #include "bpf_kfuncs.h" 7 6 #include "bpf_misc.h" 8 7 9 8 char _license[] SEC("license") = "GPL"; ··· 15 16 __u64 test_uprobe_cookie_entry[6]; 16 17 __u64 test_uprobe_cookie_return[3]; 17 18 18 - static int check_cookie(void) 19 + static int check_cookie(struct pt_regs *ctx) 19 20 { 20 - __u64 *cookie = bpf_session_cookie(); 21 + __u64 *cookie = bpf_session_cookie(ctx); 21 22 22 - if (bpf_session_is_return()) { 23 + if (bpf_session_is_return(ctx)) { 23 24 if (idx_return >= ARRAY_SIZE(test_uprobe_cookie_return)) 24 25 return 1; 25 26 test_uprobe_cookie_return[idx_return++] = *cookie; ··· 39 40 if (bpf_get_current_pid_tgid() >> 32 != pid) 40 41 return 1; 41 42 42 - return check_cookie(); 43 + return check_cookie(ctx); 43 44 }