bpf, arm64: Add fsession support
v3 cover bpf, arm64: Add fsession support
Similar to commit 98770bd4e6df ("bpf,x86: add fsession support for x86_64"), add fsession support on arm64.
Patch #1 adds bpf_jit_supports_fsession() to prevent fsession loading on architectures that do not implement fsession support.
Patch #2 implements fsession support in the arm64 BPF JIT trampoline.
Patch #3 enables the relevant selftests on arm64, including get_func_ip, and get_func_args.
All enabled tests pass on arm64:
cd tools/testing/selftests/bpf
./test_progs -t fsession
#135/1 fsession_test/fsession_test:OK #135/2 fsession_test/fsession_reattach:OK #135/3 fsession_test/fsession_cookie:OK #135 fsession_test:OK
Summary: 1/3 PASSED, 0 SKIPPED, 0 FAILED
./test_progs -t get_func
#138 get_func_args_test:OK
#139 get_func_ip_test:OK
Summary: 2/0 PASSED, 0 SKIPPED, 0 FAILED
Changes:
v2 -> v3:
* Fix typo in subject and patch message of patch #1 (per AI and Chris).
* Collect Acked-by, and Tested-by from Puranjay, thanks.
* v2: https://lore.kernel.org/bpf/[email protected]/
v1 -> v2:
* Add bpf_jit_supports_fsession().
* v1: https://lore.kernel.org/bpf/[email protected]/
Leon Hwang (3):
bpf: Add bpf_jit_supports_fsession()
bpf, arm64: Add fsession support
selftests/bpf: Enable get_func_args and get_func_ip tests on arm64
arch/arm64/net/bpf_jit_comp.c | 71 ++++++++++++++++--- arch/x86/net/bpf_jit_comp.c | 5 ++ include/linux/bpf.h | 7 +- include/linux/filter.h | 1 + kernel/bpf/core.c | 5 ++ kernel/bpf/verifier.c | 3 + .../selftests/bpf/prog_tests/fsession_test.c | 32 ++++++--- .../selftests/bpf/progs/get_func_args_test.c | 2 +- .../selftests/bpf/progs/get_func_ip_test.c | 2 +- 9 files changed, 108 insertions(+), 20 deletions(-)
--
2.52.0
PATCH v3 1/3 bpf: Add bpf_jit_supports_fsession()
The added fsession does not prevent running on those architectures, that haven't added fsession support.
For example, try to run fsession tests on arm64:
test_fsession_basic:PASS:fsession_test__open_and_load 0 nsec test_fsession_basic:PASS:fsession_attach 0 nsec check_result:FAIL:test_run_opts err unexpected error: -14 (errno 14)
In order to prevent such errors, add bpf_jit_supports_fsession() to guard those architectures.
--- arch/x86/net/bpf_jit_comp.c | 5 +++ include/linux/filter.h | 1 + kernel/bpf/core.c | 5 +++ kernel/bpf/verifier.c | 3 ++ .../selftests/bpf/prog_tests/fsession_test.c | 32 ++++++++++++++----- 5 files changed, 38 insertions(+), 8 deletions(-)
arch/x86/net/bpf_jit_comp.c +5 -0
@@ -4112,3 +4112,8 @@ bool bpf_jit_supports_timed_may_goto(void) {return true; } + +bool bpf_jit_supports_fsession (void ) +{ +return true; +}
include/linux/filter.h +1 -0
@@ -1167,6 +1167,7 @@ bool bpf_jit_supports_arena(void);bool bpf_jit_supports_insn (struct bpf_insn *insn,bool in_arena);bool bpf_jit_supports_private_stack (void );bool bpf_jit_supports_timed_may_goto (void ); +bool bpf_jit_supports_fsession (void );u64 bpf_arch_uaddress_limit (void );void arch_bpf_stack_walk (bool (*consume_fn)(void *cookie,u64 ip,u64 sp,u64 bp),void *cookie);u64 arch_bpf_timed_may_goto (void );
kernel/bpf/core.c +5 -0
@@ -3142,6 +3142,11 @@ bool __weak bpf_jit_supports_insn(struct bpf_insn *insn, bool in_arena)return false; } +bool __weak bpf_jit_supports_fsession (void ) +{ +return false; +} +u64 __weak bpf_arch_uaddress_limit (void ) {#if defined(CONFIG_64BIT ) && defined(CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE )
kernel/bpf/verifier.c +3 -0
@@ -24874,6 +24874,9 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,case BPF_TRACE_FENTRY :case BPF_TRACE_FEXIT :case BPF_TRACE_FSESSION : +if (prog->expected_attach_type ==BPF_TRACE_FSESSION && + !bpf_jit_supports_fsession ()) +return -EOPNOTSUPP ;if (!btf_type_is_func (t)) {bpf_log (log,"attach_btf_id %u is not a function\n" , btf_id);
tools/testing/selftests/bpf/prog_tests/fsession_test.c +24 -8
@@ -29,8 +29,16 @@ static void test_fsession_basic(void)struct fsession_test *skel =NULL ;int err; - skel =fsession_test__open_and_load (); -if (!ASSERT_OK_PTR (skel,"fsession_test__open_and_load" )) + skel =fsession_test__open (); +if (!ASSERT_OK_PTR (skel,"fsession_test__open" )) +return ; + + err =fsession_test__load (skel); +if (err == -EOPNOTSUPP ) { +test__skip (); + goto cleanup; + } +if (!ASSERT_OK (err,"fsession_test__load" )) goto cleanup; err =fsession_test__attach (skel);
@@ -47,8 +55,16 @@ static void test_fsession_reattach(void)struct fsession_test *skel =NULL ;int err; - skel =fsession_test__open_and_load (); -if (!ASSERT_OK_PTR (skel,"fsession_test__open_and_load" )) + skel =fsession_test__open (); +if (!ASSERT_OK_PTR (skel,"fsession_test__open" )) +return ; + + err =fsession_test__load (skel); +if (err == -EOPNOTSUPP ) { +test__skip (); + goto cleanup; + } +if (!ASSERT_OK (err,"fsession_test__load" )) goto cleanup;/* first attach */
@@ -94,6 +110,10 @@ static void test_fsession_cookie(void)bpf_program__set_autoload (skel->progs.test6, false); err =fsession_test__load (skel); +if (err == -EOPNOTSUPP ) { +test__skip (); + goto cleanup; + }if (!ASSERT_OK (err,"fsession_test__load" )) goto cleanup;
@@ -111,10 +131,6 @@ static void test_fsession_cookie(void)void test_fsession_test (void ) { -#if !defined(__x86_64__) -test__skip (); -return ; -#endif if (test__start_subtest ("fsession_test" ))test_fsession_basic ();if (test__start_subtest ("fsession_reattach" ))
Signature · 1 line
2.52.0
[email protected]
AI reviewRe: [PATCH bpf-next v3 1/3] bpf: Add bpf_jit_supports_fsession()
This isn't a bug, but other similar bpf_jit_supports_*() checks in this file include a bpf_log() message before returning an error. For example:
kernel/bpf/verifier.c int bpf_check_attach_target(struct bpf_verifier_log *log, · line 24879
Quoted 11 lines
kernel/bpf/verifier.c +3
-0@@ -24874,6 +24874,9 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,case BPF_TRACE_FENTRY :case BPF_TRACE_FEXIT :case BPF_TRACE_FSESSION : +if (prog->expected_attach_type ==BPF_TRACE_FSESSION && + !bpf_jit_supports_fsession ()) +return -EOPNOTSUPP ;
This isn't a bug, but other similar bpf_jit_supports_*() checks in this file include a bpf_log() message before returning an error. For example:
bpf_jit_supports_kfunc_call() -> "JIT does not support calling kernel function" bpf_jit_supports_exceptions() -> "JIT does not support calling kfunc..."
bpf_jit_supports_arena() -> "JIT doesn't support arena"
bpf_jit_supports_private_stack() -> "Private stack not supported by jit"
Should this check also include a message like "JIT does not support fsession" for consistency with other similar checks in the verifier?
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/21482297342
AI-authorship-score: low
AI-authorship-explanation: The commit demonstrates specific debugging context with actual test output and errno values, correct understanding of kernel BPF conventions, and follows established patterns - typical of experienced human kernel developers.
issues-found: 1
issue-severity-score: low
issue-severity-explanation: Minor consistency issue - missing bpf_log() error message compared to similar checks in the same file; does not affect functionality or stability.
Re: [PATCH bpf-next v3 1/3] bpf: Add bpf_jit_supports_fsession()
Quoted 16 lines · bot+bpf-ci
kernel/bpf/verifier.c int bpf_check_attach_target(struct bpf_verifier_log *log, · line 24879
Quoted 11 lines
kernel/bpf/verifier.c +3
-0@@ -24874,6 +24874,9 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,case BPF_TRACE_FENTRY :case BPF_TRACE_FEXIT :case BPF_TRACE_FSESSION : +if (prog->expected_attach_type ==BPF_TRACE_FSESSION && + !bpf_jit_supports_fsession ()) +return -EOPNOTSUPP ;This isn't a bug, but other similar bpf_jit_supports_*() checks in this file include a
bpf_log()message before returning an error. For example:
Quoted 8 lines
bpf_jit_supports_kfunc_call()-> "JIT does not support calling kernel function"bpf_jit_supports_exceptions()-> "JIT does not support calling kfunc..."
bpf_jit_supports_arena()-> "JIT doesn't support arena"
bpf_jit_supports_private_stack()-> "Private stack not supported by jit"Should this check also include a message like "JIT does not support fsession" for consistency with other similar checks in the verifier?
That makes sense.
Let me add the log message.
Thanks,
Leon
Quoted 12 lines
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.mdCI run summary: https://github.com/kernel-patches/bpf/actions/runs/21482297342
AI-authorship-score: low
AI-authorship-explanation: The commit demonstrates specific debugging context with actual test output and errno values, correct understanding of kernel BPF conventions, and follows established patterns - typical of experienced human kernel developers.
issues-found: 1
issue-severity-score: low
issue-severity-explanation: Minor consistency issue - missingbpf_log()error message compared to similar checks in the same file; does not affect functionality or stability.
PATCH v3 2/3 bpf, arm64: Add fsession support
In reply to Leon HwangImplement fsession support in the arm64 BPF JIT trampoline.
Extend the trampoline stack layout to store function metadata and session cookies, and pass the appropriate metadata to fentry and fexit programs. This mirrors the existing x86 behavior and enables session cookies on arm64.
--- arch/arm64/net/bpf_jit_comp.c | 71 ++++++++++++++++++++++++++++++----- include/linux/bpf.h | 7 +++- 2 files changed, 68 insertions(+), 10 deletions(-)
arch/arm64/net/bpf_jit_comp.c +62 -9
@@ -2510,6 +2510,12 @@ static bool is_struct_ops_tramp(const struct bpf_tramp_links *fentry_links) fentry_links->links[0 ]->link.type ==BPF_LINK_TYPE_STRUCT_OPS ; } +static void store_func_meta (struct jit_ctx *ctx,u64 func_meta,int func_meta_off) +{ +emit_a64_mov_i64 (A64_R (10 ), func_meta, ctx); +emit (A64_STR64I (A64_R (10 ),A64_SP , func_meta_off), ctx); +} +/* Based on the x86's implementation of arch_prepare_bpf_trampoline(). * * bpf prog and function entry before bpf trampoline hooked:
@@ -2533,7 +2539,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,int regs_off;int retval_off;int bargs_off; -int nfuncargs_off; +int func_meta_off;int ip_off;int run_ctx_off;int oargs_off;
@@ -2544,6 +2550,9 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,bool save_ret;__le32 **branches =NULL ;bool is_struct_ops =is_struct_ops_tramp (fentry); +int cookie_off, cookie_cnt, cookie_bargs_off; +int fsession_cnt =bpf_fsession_cnt (tlinks); +u64 func_meta;/* trampoline stack layout: * [ parent ip ]
@@ -2562,10 +2571,14 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,* [ ... ] * SP + bargs_off [ arg reg 1 ] for bpf * -* SP + nfuncargs_off [ arg regs count ] +* SP + func_meta_off [ regs count, etc ] * * SP + ip_off [ traced function ] BPF_TRAMP_F_IP_ARG flag * +* [ stack cookie N ] +* [ ... ] +* SP + cookie_off [ stack cookie 1 ] +* * SP + run_ctx_off [ bpf_tramp_run_ctx ] * * [ stack arg N ]
@@ -2582,13 +2595,18 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,/* room for bpf_tramp_run_ctx */ stack_size +=round_up (sizeof (struct bpf_tramp_run_ctx ),8 ); + cookie_off = stack_size; +/* room for session cookies */ + cookie_cnt =bpf_fsession_cookie_cnt (tlinks); + stack_size += cookie_cnt *8 ; + ip_off = stack_size;/* room for IP address argument */ if (flags &BPF_TRAMP_F_IP_ARG ) stack_size +=8 ; - nfuncargs_off = stack_size; -/* room for args count */ + func_meta_off = stack_size; +/* room for function metadata, such as regs count */ stack_size +=8 ; bargs_off = stack_size;
@@ -2646,9 +2664,9 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,emit (A64_STR64I (A64_R (10 ),A64_SP , ip_off), ctx); } -/* save arg regs count*/ -emit (A64_MOVZ (1 ,A64_R (10 ), nfuncargs,0 ), ctx); -emit (A64_STR64I (A64_R (10 ),A64_SP , nfuncargs_off), ctx); +/* save function metadata */ + func_meta = nfuncargs; +store_func_meta (ctx, func_meta, func_meta_off);/* save args for bpf */ save_args (ctx, bargs_off, oargs_off, m, a, false);
@@ -2666,10 +2684,27 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,emit_call ((const u64 )__bpf_tramp_enter, ctx); } -for (i =0 ; i < fentry->nr_links; i++) +if (fsession_cnt) { +/* clear all the session cookies' value */ +emit (A64_MOVZ (1 ,A64_R (10 ),0 ,0 ), ctx); +for (int i =0 ; i < cookie_cnt; i++) +emit (A64_STR64I (A64_R (10 ),A64_SP , cookie_off +8 * i), ctx); +/* clear the return value to make sure fentry always gets 0 */ +emit (A64_STR64I (A64_R (10 ),A64_SP , retval_off), ctx); + } + + cookie_bargs_off = (bargs_off - cookie_off) /8 ; +for (i =0 ; i < fentry->nr_links; i++) { +if (bpf_link_prog_session_cookie (fentry->links[i])) { +u64 meta = func_meta | (cookie_bargs_off <<BPF_TRAMP_COOKIE_INDEX_SHIFT ); + +store_func_meta (ctx, meta, func_meta_off); + cookie_bargs_off--; + }invoke_bpf_prog (ctx, fentry->links[i], bargs_off, retval_off, run_ctx_off, flags &BPF_TRAMP_F_RET_FENTRY_RET ); + }if (fmod_ret->nr_links) { branches = kcalloc(fmod_ret->nr_links, sizeof(__le32 *),
@@ -2701,9 +2736,22 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, *branches[i] =cpu_to_le32 (A64_CBNZ (1 ,A64_R (10 ), offset)); } -for (i =0 ; i < fexit->nr_links; i++) +/* set the "is_return" flag for fsession */ + func_meta |= (1ULL <<BPF_TRAMP_IS_RETURN_SHIFT ); +if (fsession_cnt) +store_func_meta (ctx, func_meta, func_meta_off); + + cookie_bargs_off = (bargs_off - cookie_off) /8 ; +for (i =0 ; i < fexit->nr_links; i++) { +if (bpf_link_prog_session_cookie (fexit->links[i])) { +u64 meta = func_meta | (cookie_bargs_off <<BPF_TRAMP_COOKIE_INDEX_SHIFT ); + +store_func_meta (ctx, meta, func_meta_off); + cookie_bargs_off--; + }invoke_bpf_prog (ctx, fexit->links[i], bargs_off, retval_off, run_ctx_off, false); + }if (flags &BPF_TRAMP_F_CALL_ORIG ) { im->ip_epilogue = ctx->ro_image + ctx->idx;
@@ -2753,6 +2801,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,return ctx->idx; } +bool bpf_jit_supports_fsession (void ) +{ +return true; +} +int arch_bpf_trampoline_size (const struct btf_func_model *m,u32 flags,struct bpf_tramp_links *tlinks,void *func_addr) {
include/linux/bpf.h +6 -1
@@ -2195,13 +2195,18 @@ static inline int bpf_fsession_cnt(struct bpf_tramp_links *links)return cnt; } +static inline bool bpf_link_prog_session_cookie (struct bpf_tramp_link *link) +{ +return link->link.prog->call_session_cookie; +} +static inline int bpf_fsession_cookie_cnt (struct bpf_tramp_links *links) {struct bpf_tramp_links fentries = links[BPF_TRAMP_FENTRY ];int cnt =0 ;for (int i =0 ; i < links[BPF_TRAMP_FENTRY ].nr_links; i++) { -if (fentries.links[i]->link.prog->call_session_cookie) +if (bpf_link_prog_session_cookie (fentries.links[i])) cnt++; }
Signature · 1 line
2.52.0
PATCH v3 3/3 selftests/bpf: Enable get_func_args and get_func_ip tests on arm64
In reply to Leon HwangAllow get_func_args, and get_func_ip fsession selftests to run on arm64.
--- tools/testing/selftests/bpf/progs/get_func_args_test.c | 2 +- tools/testing/selftests/bpf/progs/get_func_ip_test.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
tools/testing/selftests/bpf/progs/get_func_args_test.c +1 -1
@@ -167,7 +167,7 @@ int BPF_PROG(tp_test2) }__u64 test7_result =0 ; -#ifdef __TARGET_ARCH_x86 +#if defined(bpf_target_x86) || defined(bpf_target_arm64) SEC("fsession/bpf_fentry_test1")int BPF_PROG (test7 ) {
tools/testing/selftests/bpf/progs/get_func_ip_test.c +1 -1
@@ -106,7 +106,7 @@ int BPF_URETPROBE(test8, int ret)__u64 test9_entry_result =0 ;__u64 test9_exit_result =0 ; -#ifdef __TARGET_ARCH_x86 +#if defined(bpf_target_x86) || defined(bpf_target_arm64) SEC("fsession/bpf_fentry_test1")int BPF_PROG (test9 ,int a) {
Signature · 1 line
2.52.0