* [PATCH bpf-next v7 0/2] Introduce jit_required to prevent a kernel panic @ 2026-07-02 14:36 Tiezhu Yang 2026-07-02 14:36 ` [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path Tiezhu Yang 2026-07-02 14:36 ` [PATCH bpf-next v7 2/2] bpf: Reject programs with inlined helpers if JIT is unavailable Tiezhu Yang 0 siblings, 2 replies; 19+ messages in thread From: Tiezhu Yang @ 2026-07-02 14:36 UTC (permalink / raw) To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, KaFai Wan Cc: bpf, loongarch, Leon Hwang, Puranjay Mohan, Björn Töpel This series introduces a 'jit_required' flag in struct bpf_prog to track programs that strictly require JIT. The aim is to reject loading programs with inlined helpers when JIT is unavailable to prevent a kernel panic. Tiezhu Yang (2): bpf: Introduce jit_required flag and refactor kfunc path bpf: Reject programs with inlined helpers if JIT is unavailable include/linux/bpf.h | 3 ++- kernel/bpf/core.c | 3 +-- kernel/bpf/fixups.c | 4 +++- kernel/bpf/verifier.c | 2 ++ 4 files changed, 8 insertions(+), 4 deletions(-) -- 2.42.0 ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-02 14:36 [PATCH bpf-next v7 0/2] Introduce jit_required to prevent a kernel panic Tiezhu Yang @ 2026-07-02 14:36 ` Tiezhu Yang 2026-07-02 14:58 ` sashiko-bot 2026-07-03 13:55 ` KaFai Wan 2026-07-02 14:36 ` [PATCH bpf-next v7 2/2] bpf: Reject programs with inlined helpers if JIT is unavailable Tiezhu Yang 1 sibling, 2 replies; 19+ messages in thread From: Tiezhu Yang @ 2026-07-02 14:36 UTC (permalink / raw) To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, KaFai Wan Cc: bpf, loongarch, Leon Hwang, Puranjay Mohan, Björn Töpel Introduce a 'jit_required' bitfield flag at the end of the flags group in struct bpf_prog. This bit tracks whether a program strictly requires the JIT compiler. Set this flag to 1 when a kfunc call is added at the end of bpf_add_kfunc_call(). In __bpf_prog_select_runtime(), check with fp->jit_required rather than bpf_prog_has_kfunc_call() to unify the logic. Suggested-by: Alexei Starovoitov <ast@kernel.org> Suggested-by: KaFai Wan <kafai.wan@linux.dev> Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn> --- include/linux/bpf.h | 3 ++- kernel/bpf/core.c | 3 +-- kernel/bpf/verifier.c | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index ba09795e0bfd..4e2b059d71f3 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1880,7 +1880,8 @@ struct bpf_prog { call_get_func_ip:1, /* Do we call get_func_ip() */ call_session_cookie:1, /* Do we call bpf_session_cookie() */ tstamp_type_access:1, /* Accessed __sk_buff->tstamp_type */ - sleepable:1; /* BPF program is sleepable */ + sleepable:1, /* BPF program is sleepable */ + jit_required:1; /* program strictly requires JIT compiler */ enum bpf_prog_type type; /* Type of BPF program */ enum bpf_attach_type expected_attach_type; /* For some prog types */ u32 len; /* Number of filter blocks */ diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 649cce41e13f..5fcd19ccb41a 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -2619,8 +2619,7 @@ struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct if (fp->bpf_func) goto finalize; - if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || - bpf_prog_has_kfunc_call(fp)) + if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || fp->jit_required) jit_needed = true; if (!bpf_prog_select_interpreter(fp)) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 25aea4271cd0..f496b45b9da4 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2765,6 +2765,8 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 offset) desc->func_model = func_model; sort(tab->descs, tab->nr_descs, sizeof(tab->descs[0]), kfunc_desc_cmp_by_id_off, NULL); + + env->prog->jit_required = 1; return 0; } -- 2.42.0 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-02 14:36 ` [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path Tiezhu Yang @ 2026-07-02 14:58 ` sashiko-bot 2026-07-03 2:57 ` Tiezhu Yang 2026-07-03 13:55 ` KaFai Wan 1 sibling, 1 reply; 19+ messages in thread From: sashiko-bot @ 2026-07-02 14:58 UTC (permalink / raw) To: Tiezhu Yang; +Cc: bpf Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] The `bpf_fixup_call_args()` function and `bpf_prog_has_kfunc_call()` macro were not updated to use the new `jit_required` flag, leading to inconsistent interpreter fallback behavior for pruned kfuncs. -- commit 5a3f8861c2b6916fe194f97a407cb7265f545fd0 Author: Tiezhu Yang <yangtiezhu@loongson.cn> bpf: Introduce jit_required flag and refactor kfunc path Introduce a 'jit_required' bitfield flag at the end of the flags group in struct bpf_prog. This bit tracks whether a program strictly requires the JIT compiler. > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c > index 649cce41e13f3..5fcd19ccb41a9 100644 > --- a/kernel/bpf/core.c > +++ b/kernel/bpf/core.c > @@ -2619,8 +2619,7 @@ struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct > if (fp->bpf_func) > goto finalize; > > - if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || > - bpf_prog_has_kfunc_call(fp)) > + if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || fp->jit_required) > jit_needed = true; > > if (!bpf_prog_select_interpreter(fp)) [Severity: Medium] Since bpf_prog_has_kfunc_call() was replaced here with fp->jit_required, should bpf_fixup_call_args() in kernel/bpf/fixups.c also be updated to use the new flag? Currently, bpf_fixup_call_args() still calls bpf_prog_has_kfunc_call(). If a program has a pruned kfunc (allocating kfunc_tab but leaving jit_required=0) and JIT falls back to the interpreter, wouldn't bpf_fixup_call_args() incorrectly reject the program with -EINVAL? kernel/bpf/fixups.c:bpf_fixup_call_args() { ... bool has_kfunc_call = bpf_prog_has_kfunc_call(prog); ... if (has_kfunc_call) { verbose(env, "calling kernel functions are not allowed in non-JITed programs\n"); return -EINVAL; } ... } Should bpf_prog_has_kfunc_call() in kernel/bpf/verifier.c be updated to check prog->jit_required, or removed entirely in favor of checking the flag directly? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260702143656.28845-1-yangtiezhu@loongson.cn?part=1 ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-02 14:58 ` sashiko-bot @ 2026-07-03 2:57 ` Tiezhu Yang 2026-07-03 5:24 ` Leon Hwang 2026-07-03 13:51 ` KaFai Wan 0 siblings, 2 replies; 19+ messages in thread From: Tiezhu Yang @ 2026-07-03 2:57 UTC (permalink / raw) To: sashiko-reviews; +Cc: bpf, Alexei Starovoitov, KaFai Wan On 2026/7/2 下午10:58, sashiko-bot@kernel.org wrote: > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > - [Medium] The `bpf_fixup_call_args()` function and `bpf_prog_has_kfunc_call()` macro were not updated to use the new `jit_required` flag, leading to inconsistent interpreter fallback behavior for pruned kfuncs. > -- > > commit 5a3f8861c2b6916fe194f97a407cb7265f545fd0 > Author: Tiezhu Yang <yangtiezhu@loongson.cn> > > bpf: Introduce jit_required flag and refactor kfunc path > > Introduce a 'jit_required' bitfield flag at the end of the > flags group in struct bpf_prog. This bit tracks whether a > program strictly requires the JIT compiler. > >> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c >> index 649cce41e13f3..5fcd19ccb41a9 100644 >> --- a/kernel/bpf/core.c >> +++ b/kernel/bpf/core.c >> @@ -2619,8 +2619,7 @@ struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct >> if (fp->bpf_func) >> goto finalize; >> >> - if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || >> - bpf_prog_has_kfunc_call(fp)) >> + if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || fp->jit_required) >> jit_needed = true; >> >> if (!bpf_prog_select_interpreter(fp)) > > [Severity: Medium] > Since bpf_prog_has_kfunc_call() was replaced here with fp->jit_required, > should bpf_fixup_call_args() in kernel/bpf/fixups.c also be updated to use > the new flag? > > Currently, bpf_fixup_call_args() still calls bpf_prog_has_kfunc_call(). If > a program has a pruned kfunc (allocating kfunc_tab but leaving > jit_required=0) and JIT falls back to the interpreter, wouldn't > bpf_fixup_call_args() incorrectly reject the program with -EINVAL? > > kernel/bpf/fixups.c:bpf_fixup_call_args() { > ... > bool has_kfunc_call = bpf_prog_has_kfunc_call(prog); > ... > if (has_kfunc_call) { > verbose(env, "calling kernel functions are not allowed in non-JITed programs\n"); > return -EINVAL; > } > ... > } > > Should bpf_prog_has_kfunc_call() in kernel/bpf/verifier.c be updated to > check prog->jit_required, or removed entirely in favor of checking the flag > directly? I think it is wrong to remove bpf_prog_has_kfunc_call() entirely, because using prog->jit_required directly in bpf_fixup_call_args() would cause false positives. I tested the following changes: ``` diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 4e2b059d71f3..3a2fc194e2bb 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -3171,7 +3171,6 @@ const struct bpf_func_proto *bpf_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog); void bpf_task_storage_free(struct task_struct *task); void bpf_cgrp_storage_free(struct cgroup *cgroup); -bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog); const struct btf_func_model * bpf_jit_find_kfunc_model(const struct bpf_prog *prog, const struct bpf_insn *insn); @@ -3510,11 +3509,6 @@ static inline void bpf_task_storage_free(struct task_struct *task) { } -static inline bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) -{ - return false; -} - static inline const struct btf_func_model * bpf_jit_find_kfunc_model(const struct bpf_prog *prog, const struct bpf_insn *insn) diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c index 94e0457a0aa3..7fb92b5fa415 100644 --- a/kernel/bpf/fixups.c +++ b/kernel/bpf/fixups.c @@ -1378,7 +1378,6 @@ int bpf_fixup_call_args(struct bpf_verifier_env *env) #ifndef CONFIG_BPF_JIT_ALWAYS_ON struct bpf_prog *prog = env->prog; struct bpf_insn *insn = prog->insnsi; - bool has_kfunc_call = bpf_prog_has_kfunc_call(prog); int depth; #endif int i, err = 0; @@ -1404,7 +1403,7 @@ int bpf_fixup_call_args(struct bpf_verifier_env *env) return err; } #ifndef CONFIG_BPF_JIT_ALWAYS_ON - if (has_kfunc_call) { + if (prog->jit_required) { verbose(env, "calling kernel functions are not allowed in non-JITed programs\n"); return -EINVAL; } diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index f496b45b9da4..3dbed3047254 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2770,11 +2770,6 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 offset) return 0; } -bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) -{ - return !!prog->aux->kfunc_tab; -} - static int add_subprog_and_kfunc(struct bpf_verifier_env *env) { struct bpf_subprog_info *subprog = env->subprog_info; ``` Here is the local test log: ``` fedora@linux:~$ cat test_panic.c #include <linux/bpf.h> #include <bpf/bpf_helpers.h> SEC("kprobe/sys_getpid") int test_panic(void *ctx) { struct task_struct *task; task = (struct task_struct *)bpf_get_current_task(); if (task) bpf_printk("Task address: %p\n", task); return 0; } char LICENSE[] SEC("license") = "GPL"; fedora@linux:~$ clang -target bpf -O2 -g -c test_panic.c -o test_panic.o fedora@linux:~$ sudo sysctl -w net.core.bpf_jit_enable=0 [sudo] password for fedora: net.core.bpf_jit_enable = 0 fedora@linux:~$ sudo bpftool prog load test_panic.o /sys/fs/bpf/test_panic autoattach libbpf: prog 'test_panic': BPF program load failed: Invalid argument libbpf: prog 'test_panic': -- BEGIN PROG LOAD LOG -- calling kernel functions are not allowed in non-JITed programs processed 10 insns (limit 1000000) max_states_per_insn 0 total_states 1 peak_states 1 mark_read 0 -- END PROG LOAD LOG -- libbpf: prog 'test_panic': failed to load: -22 libbpf: failed to load object 'test_panic.o' Error: failed to load object file ``` This change incorrectly rejects programs that only contain normal inlined helper calls with -EINVAL. Instead, I think bpf_prog_has_kfunc_call() should be updated to check prog->jit_required, like so: ``` diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index f496b45b9da4..1f5824c1c691 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2772,7 +2772,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 offset) bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) { - return !!prog->aux->kfunc_tab; + return prog->jit_required && !!prog->aux->kfunc_tab; } static int add_subprog_and_kfunc(struct bpf_verifier_env *env) ``` Here is the local test log: ``` fedora@linux:~$ cat test_panic.c #include <linux/bpf.h> #include <bpf/bpf_helpers.h> SEC("kprobe/sys_getpid") int test_panic(void *ctx) { struct task_struct *task; task = (struct task_struct *)bpf_get_current_task(); if (task) bpf_printk("Task address: %p\n", task); return 0; } char LICENSE[] SEC("license") = "GPL"; fedora@linux:~$ clang -target bpf -O2 -g -c test_panic.c -o test_panic.o fedora@linux:~$ sudo sysctl -w net.core.bpf_jit_enable=0 [sudo] password for fedora: net.core.bpf_jit_enable = 0 fedora@linux:~$ sudo bpftool prog load test_panic.o /sys/fs/bpf/test_panic autoattach libbpf: prog 'test_panic': BPF program load failed: unknown error (-524) libbpf: prog 'test_panic': -- BEGIN PROG LOAD LOG -- processed 10 insns (limit 1000000) max_states_per_insn 0 total_states 1 peak_states 1 mark_read 0 -- END PROG LOAD LOG -- libbpf: prog 'test_panic': failed to load: -524 libbpf: failed to load object 'test_panic.o' Error: failed to load object file ``` This ensures that pruned kfuncs (allocating kfunc_tab but leaving jit_required=0) safely return false, at the same time, this check perfectly isolates normal inlined helper paths. Let me wait for more review comments and will send v8 next week. Thanks, Tiezhu ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-03 2:57 ` Tiezhu Yang @ 2026-07-03 5:24 ` Leon Hwang 2026-07-03 6:59 ` Tiezhu Yang 2026-07-03 13:51 ` KaFai Wan 1 sibling, 1 reply; 19+ messages in thread From: Leon Hwang @ 2026-07-03 5:24 UTC (permalink / raw) To: Tiezhu Yang, sashiko-reviews; +Cc: bpf, Alexei Starovoitov, KaFai Wan On 3/7/26 10:57, Tiezhu Yang wrote: > On 2026/7/2 下午10:58, sashiko-bot@kernel.org wrote: [...] >>> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c >>> index 649cce41e13f3..5fcd19ccb41a9 100644 >>> --- a/kernel/bpf/core.c >>> +++ b/kernel/bpf/core.c >>> @@ -2619,8 +2619,7 @@ struct bpf_prog >>> *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct >>> if (fp->bpf_func) >>> goto finalize; >>> - if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || >>> - bpf_prog_has_kfunc_call(fp)) >>> + if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || fp->jit_required) >>> jit_needed = true; >>> if (!bpf_prog_select_interpreter(fp)) >> >> [Severity: Medium] >> Since bpf_prog_has_kfunc_call() was replaced here with fp->jit_required, >> should bpf_fixup_call_args() in kernel/bpf/fixups.c also be updated to >> use >> the new flag? >> >> Currently, bpf_fixup_call_args() still calls >> bpf_prog_has_kfunc_call(). If >> a program has a pruned kfunc (allocating kfunc_tab but leaving >> jit_required=0) and JIT falls back to the interpreter, wouldn't >> bpf_fixup_call_args() incorrectly reject the program with -EINVAL? I think this rejection is intentional. '!!prog->aux->kfunc_tab' means there is kfunc call in the prog, even though the kfunc call could be pruned. >> >> kernel/bpf/fixups.c:bpf_fixup_call_args() { >> ... >> bool has_kfunc_call = bpf_prog_has_kfunc_call(prog); >> ... >> if (has_kfunc_call) { >> verbose(env, "calling kernel functions are not allowed in non- >> JITed programs\n"); >> return -EINVAL; >> } >> ... >> } [...] > ``` > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index f496b45b9da4..1f5824c1c691 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -2772,7 +2772,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env > *env, u32 func_id, u16 offset) > > bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) > { > - return !!prog->aux->kfunc_tab; > + return prog->jit_required && !!prog->aux->kfunc_tab; When 'prog->jit_required' is used for JIT-inlineable helper call, this change could also cause false positive for the above pruned kfunc case. If you don't want bpf_fixup_call_args() rejects the program with -EINVAL for the pruned kfunc case, suggest moving 'if (!func_id && !offset)' before the tab allocation in bpf_add_kfunc_call(). Thanks, Leon > } > [...] ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-03 5:24 ` Leon Hwang @ 2026-07-03 6:59 ` Tiezhu Yang 2026-07-03 14:14 ` Leon Hwang 0 siblings, 1 reply; 19+ messages in thread From: Tiezhu Yang @ 2026-07-03 6:59 UTC (permalink / raw) To: Leon Hwang, sashiko-reviews; +Cc: bpf, Alexei Starovoitov, KaFai Wan On 2026/7/3 下午1:24, Leon Hwang wrote: > On 3/7/26 10:57, Tiezhu Yang wrote: >> On 2026/7/2 下午10:58, sashiko-bot@kernel.org wrote: > [...] >>>> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c >>>> index 649cce41e13f3..5fcd19ccb41a9 100644 >>>> --- a/kernel/bpf/core.c >>>> +++ b/kernel/bpf/core.c >>>> @@ -2619,8 +2619,7 @@ struct bpf_prog >>>> *__bpf_prog_select_runtime(struct bpf_verifier_env *env, struct >>>> if (fp->bpf_func) >>>> goto finalize; >>>> - if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || >>>> - bpf_prog_has_kfunc_call(fp)) >>>> + if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || fp->jit_required) >>>> jit_needed = true; >>>> if (!bpf_prog_select_interpreter(fp)) >>> >>> [Severity: Medium] >>> Since bpf_prog_has_kfunc_call() was replaced here with fp->jit_required, >>> should bpf_fixup_call_args() in kernel/bpf/fixups.c also be updated to >>> use >>> the new flag? >>> >>> Currently, bpf_fixup_call_args() still calls >>> bpf_prog_has_kfunc_call(). If >>> a program has a pruned kfunc (allocating kfunc_tab but leaving >>> jit_required=0) and JIT falls back to the interpreter, wouldn't >>> bpf_fixup_call_args() incorrectly reject the program with -EINVAL? > > > I think this rejection is intentional. '!!prog->aux->kfunc_tab' means > there is kfunc call in the prog, even though the kfunc call could be pruned. > >>> >>> kernel/bpf/fixups.c:bpf_fixup_call_args() { >>> ... >>> bool has_kfunc_call = bpf_prog_has_kfunc_call(prog); >>> ... >>> if (has_kfunc_call) { >>> verbose(env, "calling kernel functions are not allowed in non- >>> JITed programs\n"); >>> return -EINVAL; >>> } >>> ... >>> } > > [...] > >> ``` >> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c >> index f496b45b9da4..1f5824c1c691 100644 >> --- a/kernel/bpf/verifier.c >> +++ b/kernel/bpf/verifier.c >> @@ -2772,7 +2772,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env >> *env, u32 func_id, u16 offset) >> >> bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) >> { >> - return !!prog->aux->kfunc_tab; >> + return prog->jit_required && !!prog->aux->kfunc_tab; > > > When 'prog->jit_required' is used for JIT-inlineable helper call, this > change could also cause false positive for the above pruned kfunc case. > > If you don't want bpf_fixup_call_args() rejects the program with -EINVAL > for the pruned kfunc case, suggest moving 'if (!func_id && !offset)' > before the tab allocation in bpf_add_kfunc_call(). How about this: ``` diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 25aea4271cd0..c34cc524651a 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2770,7 +2770,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 offset) bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) { - return !!prog->aux->kfunc_tab; + return prog->aux->kfunc_tab && prog->aux->kfunc_tab->nr_descs > 0; } static int add_subprog_and_kfunc(struct bpf_verifier_env *env) ``` IMO, there are no side effects for the following four cases: 1. Pure JIT-inlined Helper 2. Pure Pruned kfunc 3. Pruned kfunc + Inlined Helper 4. Active (Unpruned) kfunc Thanks, Tiezhu ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-03 6:59 ` Tiezhu Yang @ 2026-07-03 14:14 ` Leon Hwang 2026-07-03 15:53 ` Tiezhu Yang 0 siblings, 1 reply; 19+ messages in thread From: Leon Hwang @ 2026-07-03 14:14 UTC (permalink / raw) To: Tiezhu Yang, sashiko-reviews; +Cc: bpf, Alexei Starovoitov, KaFai Wan On 2026/7/3 14:59, Tiezhu Yang wrote: [...] >>> ``` >>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c >>> index f496b45b9da4..1f5824c1c691 100644 >>> --- a/kernel/bpf/verifier.c >>> +++ b/kernel/bpf/verifier.c >>> @@ -2772,7 +2772,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env >>> *env, u32 func_id, u16 offset) >>> >>> bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) >>> { >>> - return !!prog->aux->kfunc_tab; >>> + return prog->jit_required && !!prog->aux->kfunc_tab; >> >> >> When 'prog->jit_required' is used for JIT-inlineable helper call, this >> change could also cause false positive for the above pruned kfunc case. >> >> If you don't want bpf_fixup_call_args() rejects the program with -EINVAL >> for the pruned kfunc case, suggest moving 'if (!func_id && !offset)' >> before the tab allocation in bpf_add_kfunc_call(). > > How about this: > > ``` > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index 25aea4271cd0..c34cc524651a 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -2770,7 +2770,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env > *env, u32 func_id, u16 offset) > > bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) > { > - return !!prog->aux->kfunc_tab; > + return prog->aux->kfunc_tab && prog->aux->kfunc_tab->nr_descs > 0; NIT: drop '> 0' Looks better. > } > > static int add_subprog_and_kfunc(struct bpf_verifier_env *env) > ``` > IMO, there are no side effects for the following four cases: > > 1. Pure JIT-inlined Helper > 2. Pure Pruned kfunc > 3. Pruned kfunc + Inlined Helper > 4. Active (Unpruned) kfunc > This change allows pruned kfunc + interpreter fallback and pruned kfunc + bpf_fixup_call_args(), when CONFIG_BPF_JIT_ALWAYS_ON is off. Does it look like a pre-existing issue? Pls read "Support kernel module function calls from eBPF" [1] to understand the background of introducing func_id=0 kfunc. [1] https://lore.kernel.org/bpf/20211002011757.311265-1-memxor@gmail.com/ Thanks, Leon ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-03 14:14 ` Leon Hwang @ 2026-07-03 15:53 ` Tiezhu Yang 2026-07-04 1:17 ` KaFai Wan 0 siblings, 1 reply; 19+ messages in thread From: Tiezhu Yang @ 2026-07-03 15:53 UTC (permalink / raw) To: Leon Hwang, sashiko-reviews; +Cc: bpf, Alexei Starovoitov, KaFai Wan On 7/3/26 22:14, Leon Hwang wrote: > On 2026/7/3 14:59, Tiezhu Yang wrote: > [...] >>>> ``` >>>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c >>>> index f496b45b9da4..1f5824c1c691 100644 >>>> --- a/kernel/bpf/verifier.c >>>> +++ b/kernel/bpf/verifier.c >>>> @@ -2772,7 +2772,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env >>>> *env, u32 func_id, u16 offset) >>>> >>>> bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) >>>> { >>>> - return !!prog->aux->kfunc_tab; >>>> + return prog->jit_required && !!prog->aux->kfunc_tab; >>> >>> >>> When 'prog->jit_required' is used for JIT-inlineable helper call, this >>> change could also cause false positive for the above pruned kfunc case. >>> >>> If you don't want bpf_fixup_call_args() rejects the program with -EINVAL >>> for the pruned kfunc case, suggest moving 'if (!func_id && !offset)' >>> before the tab allocation in bpf_add_kfunc_call(). >> >> How about this: >> >> ``` >> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c >> index 25aea4271cd0..c34cc524651a 100644 >> --- a/kernel/bpf/verifier.c >> +++ b/kernel/bpf/verifier.c >> @@ -2770,7 +2770,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env >> *env, u32 func_id, u16 offset) >> >> bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) >> { >> - return !!prog->aux->kfunc_tab; >> + return prog->aux->kfunc_tab && prog->aux->kfunc_tab->nr_descs > 0; > > > NIT: drop '> 0' > > Looks better. OK, will do it in v8. > >> } >> >> static int add_subprog_and_kfunc(struct bpf_verifier_env *env) >> ``` >> IMO, there are no side effects for the following four cases: >> >> 1. Pure JIT-inlined Helper >> 2. Pure Pruned kfunc >> 3. Pruned kfunc + Inlined Helper >> 4. Active (Unpruned) kfunc >> > > This change allows pruned kfunc + interpreter fallback and pruned kfunc > + bpf_fixup_call_args(), when CONFIG_BPF_JIT_ALWAYS_ON is off. > > Does it look like a pre-existing issue? I think so. > > Pls read "Support kernel module function calls from eBPF" [1] to > understand the background of introducing func_id=0 kfunc. > > [1] https://lore.kernel.org/bpf/20211002011757.311265-1-memxor@gmail.com/ > > Thanks, > Leon Thanks, Tiezhu ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-03 15:53 ` Tiezhu Yang @ 2026-07-04 1:17 ` KaFai Wan 0 siblings, 0 replies; 19+ messages in thread From: KaFai Wan @ 2026-07-04 1:17 UTC (permalink / raw) To: Tiezhu Yang, Leon Hwang, sashiko-reviews; +Cc: bpf, Alexei Starovoitov On Fri, 2026-07-03 at 23:53 +0800, Tiezhu Yang wrote: > On 7/3/26 22:14, Leon Hwang wrote: > > On 2026/7/3 14:59, Tiezhu Yang wrote: > > [...] > > > > > ``` > > > > > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > > > > > index f496b45b9da4..1f5824c1c691 100644 > > > > > --- a/kernel/bpf/verifier.c > > > > > +++ b/kernel/bpf/verifier.c > > > > > @@ -2772,7 +2772,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env > > > > > *env, u32 func_id, u16 offset) > > > > > > > > > > bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) > > > > > { > > > > > - return !!prog->aux->kfunc_tab; > > > > > + return prog->jit_required && !!prog->aux->kfunc_tab; > > > > > > > > > > > > When 'prog->jit_required' is used for JIT-inlineable helper call, this > > > > change could also cause false positive for the above pruned kfunc case. > > > > > > > > If you don't want bpf_fixup_call_args() rejects the program with -EINVAL > > > > for the pruned kfunc case, suggest moving 'if (!func_id && !offset)' > > > > before the tab allocation in bpf_add_kfunc_call(). > > > > > > How about this: > > > > > > ``` > > > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > > > index 25aea4271cd0..c34cc524651a 100644 > > > --- a/kernel/bpf/verifier.c > > > +++ b/kernel/bpf/verifier.c > > > @@ -2770,7 +2770,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env > > > *env, u32 func_id, u16 offset) > > > > > > bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) > > > { > > > - return !!prog->aux->kfunc_tab; > > > + return prog->aux->kfunc_tab && prog->aux->kfunc_tab->nr_descs > 0; > > > > > > NIT: drop '> 0' > > > > Looks better. > > OK, will do it in v8. > > > > > > } > > > > > > static int add_subprog_and_kfunc(struct bpf_verifier_env *env) > > > ``` > > > IMO, there are no side effects for the following four cases: > > > > > > 1. Pure JIT-inlined Helper > > > 2. Pure Pruned kfunc > > > 3. Pruned kfunc + Inlined Helper > > > 4. Active (Unpruned) kfunc > > > > > > > This change allows pruned kfunc + interpreter fallback and pruned kfunc > > + bpf_fixup_call_args(), when CONFIG_BPF_JIT_ALWAYS_ON is off. > > > > Does it look like a pre-existing issue? > > I think so. no, it's not. for kfunc insn, ->imm means btf_id and ->off leads to fd of btf file. we replace ->imm to actual address and reject invalid kfunc in bpf_fixup_kfunc_call(). all pruned kfuncs allowed in bpf_add_kfunc_call() are rejected in bpf_fixup_kfunc_call(), before call bpf_fixup_call_args(), no pruned kfuncs fall back to the interpreter. I think we can set ->jit_required at the entry of bpf_add_kfunc_call() instead of end, make less confusion of AI. diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index d46f7db20d8f..4f7b43ab3729 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2713,6 +2713,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 offset) return -ENOMEM; prog_aux->kfunc_tab = tab; } + env->prog->jit_required = 1; /* func_id == 0 is always invalid, but instead of returning an error, be * conservative and wait until the code elimination pass before returning > > > > > Pls read "Support kernel module function calls from eBPF" [1] to > > understand the background of introducing func_id=0 kfunc. > > > > [1] https://lore.kernel.org/bpf/20211002011757.311265-1-memxor@gmail.com/ > > > > Thanks, > > Leon > > Thanks, > Tiezhu > -- Thanks, KaFai ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-03 2:57 ` Tiezhu Yang 2026-07-03 5:24 ` Leon Hwang @ 2026-07-03 13:51 ` KaFai Wan 2026-07-03 15:56 ` Tiezhu Yang 1 sibling, 1 reply; 19+ messages in thread From: KaFai Wan @ 2026-07-03 13:51 UTC (permalink / raw) To: Tiezhu Yang, sashiko-reviews; +Cc: bpf, Alexei Starovoitov On Fri, 2026-07-03 at 10:57 +0800, Tiezhu Yang wrote: > On 2026/7/2 下午10:58, sashiko-bot@kernel.org wrote: > > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > > - [Medium] The `bpf_fixup_call_args()` function and `bpf_prog_has_kfunc_call()` macro were not > > updated to use the new `jit_required` flag, leading to inconsistent interpreter fallback > > behavior for pruned kfuncs. > > -- > > > > commit 5a3f8861c2b6916fe194f97a407cb7265f545fd0 > > Author: Tiezhu Yang <yangtiezhu@loongson.cn> > > > > bpf: Introduce jit_required flag and refactor kfunc path > > > > Introduce a 'jit_required' bitfield flag at the end of the > > flags group in struct bpf_prog. This bit tracks whether a > > program strictly requires the JIT compiler. > > > > > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c > > > index 649cce41e13f3..5fcd19ccb41a9 100644 > > > --- a/kernel/bpf/core.c > > > +++ b/kernel/bpf/core.c > > > @@ -2619,8 +2619,7 @@ struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, > > > struct > > > if (fp->bpf_func) > > > goto finalize; > > > > > > - if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || > > > - bpf_prog_has_kfunc_call(fp)) > > > + if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || fp->jit_required) > > > jit_needed = true; > > > > > > if (!bpf_prog_select_interpreter(fp)) > > > > [Severity: Medium] > > Since bpf_prog_has_kfunc_call() was replaced here with fp->jit_required, > > should bpf_fixup_call_args() in kernel/bpf/fixups.c also be updated to use > > the new flag? > > > > Currently, bpf_fixup_call_args() still calls bpf_prog_has_kfunc_call(). If > > a program has a pruned kfunc (allocating kfunc_tab but leaving > > jit_required=0) and JIT falls back to the interpreter, wouldn't > > bpf_fixup_call_args() incorrectly reject the program with -EINVAL? > > > > kernel/bpf/fixups.c:bpf_fixup_call_args() { > > ... > > bool has_kfunc_call = bpf_prog_has_kfunc_call(prog); > > ... > > if (has_kfunc_call) { > > verbose(env, "calling kernel functions are not allowed in non-JITed > > programs\n"); > > return -EINVAL; > > } > > ... > > } > > > > Should bpf_prog_has_kfunc_call() in kernel/bpf/verifier.c be updated to > > check prog->jit_required, or removed entirely in favor of checking the flag > > directly? > > I think it is wrong to remove bpf_prog_has_kfunc_call() entirely, I think it is ok to remove bpf_prog_has_kfunc_call() but with some changes. see below. > because using prog->jit_required directly in bpf_fixup_call_args() > would cause false positives. > > I tested the following changes: > > ``` > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index 4e2b059d71f3..3a2fc194e2bb 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -3171,7 +3171,6 @@ const struct bpf_func_proto > *bpf_base_func_proto(enum bpf_func_id func_id, > const struct bpf_prog > *prog); > void bpf_task_storage_free(struct task_struct *task); > void bpf_cgrp_storage_free(struct cgroup *cgroup); > -bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog); > const struct btf_func_model * > bpf_jit_find_kfunc_model(const struct bpf_prog *prog, > const struct bpf_insn *insn); > @@ -3510,11 +3509,6 @@ static inline void bpf_task_storage_free(struct > task_struct *task) > { > } > > -static inline bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) > -{ > - return false; > -} > - > static inline const struct btf_func_model * > bpf_jit_find_kfunc_model(const struct bpf_prog *prog, > const struct bpf_insn *insn) > diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c > index 94e0457a0aa3..7fb92b5fa415 100644 > --- a/kernel/bpf/fixups.c > +++ b/kernel/bpf/fixups.c > @@ -1378,7 +1378,6 @@ int bpf_fixup_call_args(struct bpf_verifier_env *env) > #ifndef CONFIG_BPF_JIT_ALWAYS_ON > struct bpf_prog *prog = env->prog; > struct bpf_insn *insn = prog->insnsi; > - bool has_kfunc_call = bpf_prog_has_kfunc_call(prog); > int depth; > #endif > int i, err = 0; > @@ -1404,7 +1403,7 @@ int bpf_fixup_call_args(struct bpf_verifier_env *env) > return err; > } > #ifndef CONFIG_BPF_JIT_ALWAYS_ON > - if (has_kfunc_call) { > + if (prog->jit_required) { > verbose(env, "calling kernel functions are not allowed > in non-JITed programs\n"); we can change the log for general purpose. patch #2 and future case will hit this too. > return -EINVAL; > } > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index f496b45b9da4..3dbed3047254 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -2770,11 +2770,6 @@ int bpf_add_kfunc_call(struct bpf_verifier_env > *env, u32 func_id, u16 offset) > return 0; > } > > -bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) > -{ > - return !!prog->aux->kfunc_tab; > -} > - > static int add_subprog_and_kfunc(struct bpf_verifier_env *env) > { > struct bpf_subprog_info *subprog = env->subprog_info; > ``` > > Here is the local test log: > > ``` > fedora@linux:~$ cat test_panic.c > #include <linux/bpf.h> > #include <bpf/bpf_helpers.h> > > SEC("kprobe/sys_getpid") > int test_panic(void *ctx) > { > struct task_struct *task; > > task = (struct task_struct *)bpf_get_current_task(); > if (task) > bpf_printk("Task address: %p\n", task); > > return 0; > } > > char LICENSE[] SEC("license") = "GPL"; > fedora@linux:~$ clang -target bpf -O2 -g -c test_panic.c -o test_panic.o > fedora@linux:~$ sudo sysctl -w net.core.bpf_jit_enable=0 > [sudo] password for fedora: > net.core.bpf_jit_enable = 0 > fedora@linux:~$ sudo bpftool prog load test_panic.o > /sys/fs/bpf/test_panic autoattach > libbpf: prog 'test_panic': BPF program load failed: Invalid argument > libbpf: prog 'test_panic': -- BEGIN PROG LOAD LOG -- > calling kernel functions are not allowed in non-JITed programs > processed 10 insns (limit 1000000) max_states_per_insn 0 total_states 1 > peak_states 1 mark_read 0 > -- END PROG LOAD LOG -- > libbpf: prog 'test_panic': failed to load: -22 > libbpf: failed to load object 'test_panic.o' > Error: failed to load object file > ``` > > This change incorrectly rejects programs that only contain normal > inlined helper calls with -EINVAL. Was it tested after compiling together with patch #2? seems patch #2 works. > > Instead, I think bpf_prog_has_kfunc_call() should be updated to check > prog->jit_required, like so: > > ``` > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index f496b45b9da4..1f5824c1c691 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -2772,7 +2772,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env > *env, u32 func_id, u16 offset) > > bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) > { > - return !!prog->aux->kfunc_tab; > + return prog->jit_required && !!prog->aux->kfunc_tab; bpf_get_current_task() is a helper, not kfunc. test_panic has no kfunc, prog->aux->kfunc_tab is null. so we get -ENOTSUPP(-524) > } > > static int add_subprog_and_kfunc(struct bpf_verifier_env *env) > ``` > > Here is the local test log: > > ``` > fedora@linux:~$ cat test_panic.c > #include <linux/bpf.h> > #include <bpf/bpf_helpers.h> > > SEC("kprobe/sys_getpid") > int test_panic(void *ctx) > { > struct task_struct *task; > > task = (struct task_struct *)bpf_get_current_task(); > if (task) > bpf_printk("Task address: %p\n", task); > > return 0; > } > > char LICENSE[] SEC("license") = "GPL"; > fedora@linux:~$ clang -target bpf -O2 -g -c test_panic.c -o test_panic.o > fedora@linux:~$ sudo sysctl -w net.core.bpf_jit_enable=0 > [sudo] password for fedora: > net.core.bpf_jit_enable = 0 > fedora@linux:~$ sudo bpftool prog load test_panic.o > /sys/fs/bpf/test_panic autoattach > libbpf: prog 'test_panic': BPF program load failed: unknown error (-524) > libbpf: prog 'test_panic': -- BEGIN PROG LOAD LOG -- > processed 10 insns (limit 1000000) max_states_per_insn 0 total_states 1 > peak_states 1 mark_read 0 > -- END PROG LOAD LOG -- > libbpf: prog 'test_panic': failed to load: -524 > libbpf: failed to load object 'test_panic.o' > Error: failed to load object file > ``` > > This ensures that pruned kfuncs (allocating kfunc_tab but leaving > jit_required=0) safely return false, at the same time, this check > perfectly isolates normal inlined helper paths. pruned kfuncs well handled in patch [1], see details in check_kfunc_call() and fixup_kfunc_call(). [1] https://lore.kernel.org/bpf/20211002011757.311265-3-memxor@gmail.com/ > > Let me wait for more review comments and will send v8 next week. > > Thanks, > Tiezhu > -- Thanks, KaFai ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-03 13:51 ` KaFai Wan @ 2026-07-03 15:56 ` Tiezhu Yang 2026-07-04 3:23 ` KaFai Wan 0 siblings, 1 reply; 19+ messages in thread From: Tiezhu Yang @ 2026-07-03 15:56 UTC (permalink / raw) To: KaFai Wan, sashiko-reviews; +Cc: bpf, Alexei Starovoitov On 7/3/26 21:51, KaFai Wan wrote: > On Fri, 2026-07-03 at 10:57 +0800, Tiezhu Yang wrote: >> On 2026/7/2 下午10:58, sashiko-bot@kernel.org wrote: >>> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: >>> - [Medium] The `bpf_fixup_call_args()` function and `bpf_prog_has_kfunc_call()` macro were not >>> updated to use the new `jit_required` flag, leading to inconsistent interpreter fallback >>> behavior for pruned kfuncs. >>> -- >>> >>> commit 5a3f8861c2b6916fe194f97a407cb7265f545fd0 >>> Author: Tiezhu Yang <yangtiezhu@loongson.cn> >>> >>> bpf: Introduce jit_required flag and refactor kfunc path >>> >>> Introduce a 'jit_required' bitfield flag at the end of the >>> flags group in struct bpf_prog. This bit tracks whether a >>> program strictly requires the JIT compiler. >>> >>>> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c >>>> index 649cce41e13f3..5fcd19ccb41a9 100644 >>>> --- a/kernel/bpf/core.c >>>> +++ b/kernel/bpf/core.c >>>> @@ -2619,8 +2619,7 @@ struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, >>>> struct >>>> if (fp->bpf_func) >>>> goto finalize; >>>> >>>> - if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || >>>> - bpf_prog_has_kfunc_call(fp)) >>>> + if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || fp->jit_required) >>>> jit_needed = true; >>>> >>>> if (!bpf_prog_select_interpreter(fp)) >>> >>> [Severity: Medium] >>> Since bpf_prog_has_kfunc_call() was replaced here with fp->jit_required, >>> should bpf_fixup_call_args() in kernel/bpf/fixups.c also be updated to use >>> the new flag? >>> >>> Currently, bpf_fixup_call_args() still calls bpf_prog_has_kfunc_call(). If >>> a program has a pruned kfunc (allocating kfunc_tab but leaving >>> jit_required=0) and JIT falls back to the interpreter, wouldn't >>> bpf_fixup_call_args() incorrectly reject the program with -EINVAL? >>> >>> kernel/bpf/fixups.c:bpf_fixup_call_args() { >>> ... >>> bool has_kfunc_call = bpf_prog_has_kfunc_call(prog); >>> ... >>> if (has_kfunc_call) { >>> verbose(env, "calling kernel functions are not allowed in non-JITed >>> programs\n"); >>> return -EINVAL; >>> } >>> ... >>> } >>> >>> Should bpf_prog_has_kfunc_call() in kernel/bpf/verifier.c be updated to >>> check prog->jit_required, or removed entirely in favor of checking the flag >>> directly? >> >> I think it is wrong to remove bpf_prog_has_kfunc_call() entirely, > > I think it is ok to remove bpf_prog_has_kfunc_call() but with some changes. see below. > >> because using prog->jit_required directly in bpf_fixup_call_args() >> would cause false positives. >> >> I tested the following changes: >> >> ``` >> diff --git a/include/linux/bpf.h b/include/linux/bpf.h >> index 4e2b059d71f3..3a2fc194e2bb 100644 >> --- a/include/linux/bpf.h >> +++ b/include/linux/bpf.h >> @@ -3171,7 +3171,6 @@ const struct bpf_func_proto >> *bpf_base_func_proto(enum bpf_func_id func_id, >> const struct bpf_prog >> *prog); >> void bpf_task_storage_free(struct task_struct *task); >> void bpf_cgrp_storage_free(struct cgroup *cgroup); >> -bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog); >> const struct btf_func_model * >> bpf_jit_find_kfunc_model(const struct bpf_prog *prog, >> const struct bpf_insn *insn); >> @@ -3510,11 +3509,6 @@ static inline void bpf_task_storage_free(struct >> task_struct *task) >> { >> } >> >> -static inline bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) >> -{ >> - return false; >> -} >> - >> static inline const struct btf_func_model * >> bpf_jit_find_kfunc_model(const struct bpf_prog *prog, >> const struct bpf_insn *insn) >> diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c >> index 94e0457a0aa3..7fb92b5fa415 100644 >> --- a/kernel/bpf/fixups.c >> +++ b/kernel/bpf/fixups.c >> @@ -1378,7 +1378,6 @@ int bpf_fixup_call_args(struct bpf_verifier_env *env) >> #ifndef CONFIG_BPF_JIT_ALWAYS_ON >> struct bpf_prog *prog = env->prog; >> struct bpf_insn *insn = prog->insnsi; >> - bool has_kfunc_call = bpf_prog_has_kfunc_call(prog); >> int depth; >> #endif >> int i, err = 0; >> @@ -1404,7 +1403,7 @@ int bpf_fixup_call_args(struct bpf_verifier_env *env) >> return err; >> } >> #ifndef CONFIG_BPF_JIT_ALWAYS_ON >> - if (has_kfunc_call) { >> + if (prog->jit_required) { >> verbose(env, "calling kernel functions are not allowed >> in non-JITed programs\n"); > > we can change the log for general purpose. patch #2 and future case will hit this too. > >> return -EINVAL; >> } >> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c >> index f496b45b9da4..3dbed3047254 100644 >> --- a/kernel/bpf/verifier.c >> +++ b/kernel/bpf/verifier.c >> @@ -2770,11 +2770,6 @@ int bpf_add_kfunc_call(struct bpf_verifier_env >> *env, u32 func_id, u16 offset) >> return 0; >> } >> >> -bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) >> -{ >> - return !!prog->aux->kfunc_tab; >> -} >> - >> static int add_subprog_and_kfunc(struct bpf_verifier_env *env) >> { >> struct bpf_subprog_info *subprog = env->subprog_info; >> ``` >> >> Here is the local test log: >> >> ``` >> fedora@linux:~$ cat test_panic.c >> #include <linux/bpf.h> >> #include <bpf/bpf_helpers.h> >> >> SEC("kprobe/sys_getpid") >> int test_panic(void *ctx) >> { >> struct task_struct *task; >> >> task = (struct task_struct *)bpf_get_current_task(); >> if (task) >> bpf_printk("Task address: %p\n", task); >> >> return 0; >> } >> >> char LICENSE[] SEC("license") = "GPL"; >> fedora@linux:~$ clang -target bpf -O2 -g -c test_panic.c -o test_panic.o >> fedora@linux:~$ sudo sysctl -w net.core.bpf_jit_enable=0 >> [sudo] password for fedora: >> net.core.bpf_jit_enable = 0 >> fedora@linux:~$ sudo bpftool prog load test_panic.o >> /sys/fs/bpf/test_panic autoattach >> libbpf: prog 'test_panic': BPF program load failed: Invalid argument >> libbpf: prog 'test_panic': -- BEGIN PROG LOAD LOG -- >> calling kernel functions are not allowed in non-JITed programs >> processed 10 insns (limit 1000000) max_states_per_insn 0 total_states 1 >> peak_states 1 mark_read 0 >> -- END PROG LOAD LOG -- >> libbpf: prog 'test_panic': failed to load: -22 >> libbpf: failed to load object 'test_panic.o' >> Error: failed to load object file >> ``` >> >> This change incorrectly rejects programs that only contain normal >> inlined helper calls with -EINVAL. > > Was it tested after compiling together with patch #2? seems patch #2 works. Yes. >> >> Instead, I think bpf_prog_has_kfunc_call() should be updated to check >> prog->jit_required, like so: >> >> ``` >> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c >> index f496b45b9da4..1f5824c1c691 100644 >> --- a/kernel/bpf/verifier.c >> +++ b/kernel/bpf/verifier.c >> @@ -2772,7 +2772,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env >> *env, u32 func_id, u16 offset) >> >> bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) >> { >> - return !!prog->aux->kfunc_tab; >> + return prog->jit_required && !!prog->aux->kfunc_tab; > > bpf_get_current_task() is a helper, not kfunc. test_panic has no kfunc, prog->aux->kfunc_tab > is null. so we get -ENOTSUPP(-524) Yes, I tested it. >> } >> >> static int add_subprog_and_kfunc(struct bpf_verifier_env *env) >> ``` >> >> Here is the local test log: >> >> ``` >> fedora@linux:~$ cat test_panic.c >> #include <linux/bpf.h> >> #include <bpf/bpf_helpers.h> >> >> SEC("kprobe/sys_getpid") >> int test_panic(void *ctx) >> { >> struct task_struct *task; >> >> task = (struct task_struct *)bpf_get_current_task(); >> if (task) >> bpf_printk("Task address: %p\n", task); >> >> return 0; >> } >> >> char LICENSE[] SEC("license") = "GPL"; >> fedora@linux:~$ clang -target bpf -O2 -g -c test_panic.c -o test_panic.o >> fedora@linux:~$ sudo sysctl -w net.core.bpf_jit_enable=0 >> [sudo] password for fedora: >> net.core.bpf_jit_enable = 0 >> fedora@linux:~$ sudo bpftool prog load test_panic.o >> /sys/fs/bpf/test_panic autoattach >> libbpf: prog 'test_panic': BPF program load failed: unknown error (-524) >> libbpf: prog 'test_panic': -- BEGIN PROG LOAD LOG -- >> processed 10 insns (limit 1000000) max_states_per_insn 0 total_states 1 >> peak_states 1 mark_read 0 >> -- END PROG LOAD LOG -- >> libbpf: prog 'test_panic': failed to load: -524 >> libbpf: failed to load object 'test_panic.o' >> Error: failed to load object file >> ``` >> >> This ensures that pruned kfuncs (allocating kfunc_tab but leaving >> jit_required=0) safely return false, at the same time, this check >> perfectly isolates normal inlined helper paths. > > pruned kfuncs well handled in patch [1], see details in check_kfunc_call() and fixup_kfunc_call(). > > [1] https://lore.kernel.org/bpf/20211002011757.311265-3-memxor@gmail.com/ >> >> Let me wait for more review comments and will send v8 next week. Thanks, Tiezhu ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-03 15:56 ` Tiezhu Yang @ 2026-07-04 3:23 ` KaFai Wan 0 siblings, 0 replies; 19+ messages in thread From: KaFai Wan @ 2026-07-04 3:23 UTC (permalink / raw) To: Tiezhu Yang, sashiko-reviews; +Cc: bpf, Alexei Starovoitov On Fri, 2026-07-03 at 23:56 +0800, Tiezhu Yang wrote: > On 7/3/26 21:51, KaFai Wan wrote: > > > > Was it tested after compiling together with patch #2? seems patch #2 works. > > Yes. > > > works as expected. -- Thanks, KaFai ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-02 14:36 ` [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path Tiezhu Yang 2026-07-02 14:58 ` sashiko-bot @ 2026-07-03 13:55 ` KaFai Wan 2026-07-03 16:14 ` Tiezhu Yang 1 sibling, 1 reply; 19+ messages in thread From: KaFai Wan @ 2026-07-03 13:55 UTC (permalink / raw) To: Tiezhu Yang, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis Cc: bpf, loongarch, Leon Hwang, Puranjay Mohan, Björn Töpel On Thu, 2026-07-02 at 22:36 +0800, Tiezhu Yang wrote: > Introduce a 'jit_required' bitfield flag at the end of the > flags group in struct bpf_prog. This bit tracks whether a > program strictly requires the JIT compiler. > > Set this flag to 1 when a kfunc call is added at the end of > bpf_add_kfunc_call(). > > In __bpf_prog_select_runtime(), check with fp->jit_required > rather than bpf_prog_has_kfunc_call() to unify the logic. > > Suggested-by: Alexei Starovoitov <ast@kernel.org> > Suggested-by: KaFai Wan <kafai.wan@linux.dev> > Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn> > --- > include/linux/bpf.h | 3 ++- > kernel/bpf/core.c | 3 +-- > kernel/bpf/verifier.c | 2 ++ > 3 files changed, 5 insertions(+), 3 deletions(-) > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index ba09795e0bfd..4e2b059d71f3 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -1880,7 +1880,8 @@ struct bpf_prog { > call_get_func_ip:1, /* Do we call get_func_ip() */ > call_session_cookie:1, /* Do we call bpf_session_cookie() */ > tstamp_type_access:1, /* Accessed __sk_buff->tstamp_type */ > - sleepable:1; /* BPF program is sleepable */ > + sleepable:1, /* BPF program is sleepable */ > + jit_required:1; /* program strictly requires JIT compiler > */ In v6 you're using 'u8 jit_required', I thought it would be 'u8 jit_required:1', so we use one byte and left 3 byte hole for future use. This version left 2 bytes hole, same as v5, but it can easily be misleading because of the u16 type, since we used 17 bits. I prefer v5, it has better readability. > enum bpf_prog_type type; /* Type of BPF program */ > enum bpf_attach_type expected_attach_type; /* For some prog types */ > u32 len; /* Number of filter blocks */ > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c > index 649cce41e13f..5fcd19ccb41a 100644 > --- a/kernel/bpf/core.c > +++ b/kernel/bpf/core.c > @@ -2619,8 +2619,7 @@ struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, > struct > if (fp->bpf_func) > goto finalize; > > - if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || > - bpf_prog_has_kfunc_call(fp)) > + if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || fp->jit_required) > jit_needed = true; > > if (!bpf_prog_select_interpreter(fp)) > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index 25aea4271cd0..f496b45b9da4 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -2765,6 +2765,8 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 > offset) > desc->func_model = func_model; > sort(tab->descs, tab->nr_descs, sizeof(tab->descs[0]), > kfunc_desc_cmp_by_id_off, NULL); > + > + env->prog->jit_required = 1; That's ok, and I think Sashiko is right about this patch. > return 0; > } > -- Thanks, KaFai ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-03 13:55 ` KaFai Wan @ 2026-07-03 16:14 ` Tiezhu Yang 2026-07-04 1:57 ` KaFai Wan 2026-07-04 2:05 ` KaFai Wan 0 siblings, 2 replies; 19+ messages in thread From: Tiezhu Yang @ 2026-07-03 16:14 UTC (permalink / raw) To: KaFai Wan, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis Cc: bpf, loongarch, Leon Hwang, Puranjay Mohan, Björn Töpel On 7/3/26 21:55, KaFai Wan wrote: > On Thu, 2026-07-02 at 22:36 +0800, Tiezhu Yang wrote: >> Introduce a 'jit_required' bitfield flag at the end of the >> flags group in struct bpf_prog. This bit tracks whether a >> program strictly requires the JIT compiler. >> >> Set this flag to 1 when a kfunc call is added at the end of >> bpf_add_kfunc_call(). >> >> In __bpf_prog_select_runtime(), check with fp->jit_required >> rather than bpf_prog_has_kfunc_call() to unify the logic. >> >> Suggested-by: Alexei Starovoitov <ast@kernel.org> >> Suggested-by: KaFai Wan <kafai.wan@linux.dev> >> Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn> >> --- >> include/linux/bpf.h | 3 ++- >> kernel/bpf/core.c | 3 +-- >> kernel/bpf/verifier.c | 2 ++ >> 3 files changed, 5 insertions(+), 3 deletions(-) >> >> diff --git a/include/linux/bpf.h b/include/linux/bpf.h >> index ba09795e0bfd..4e2b059d71f3 100644 >> --- a/include/linux/bpf.h >> +++ b/include/linux/bpf.h >> @@ -1880,7 +1880,8 @@ struct bpf_prog { >> call_get_func_ip:1, /* Do we call get_func_ip() */ >> call_session_cookie:1, /* Do we call bpf_session_cookie() */ >> tstamp_type_access:1, /* Accessed __sk_buff->tstamp_type */ >> - sleepable:1; /* BPF program is sleepable */ >> + sleepable:1, /* BPF program is sleepable */ >> + jit_required:1; /* program strictly requires JIT compiler >> */ > > In v6 you're using 'u8 jit_required', I thought it would be 'u8 jit_required:1', so we use one byte > and left 3 byte hole for future use. > > This version left 2 bytes hole, same as v5, but it can easily be misleading because of the u16 type, > since we used 17 bits. I prefer v5, it has better readability. OK, I will use the previous layout in v8, like this: ``` diff --git a/include/linux/bpf.h b/include/linux/bpf.h index ba09795e0bfd..463fae6a5c33 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1865,8 +1865,9 @@ struct bpf_prog_aux { struct bpf_prog { u16 pages; /* Number of allocated pages */ - u16 jited:1, /* Is our filter JIT'ed? */ + u32 jited:1, /* Is our filter JIT'ed? */ jit_requested:1,/* archs need to JIT the prog */ + jit_required:1, /* program strictly requires JIT compiler */ gpl_compatible:1, /* Is filter GPL compatible? */ cb_access:1, /* Is control block accessed? */ dst_needed:1, /* Do we need dst entry? */ ``` > >> enum bpf_prog_type type; /* Type of BPF program */ >> enum bpf_attach_type expected_attach_type; /* For some prog types */ >> u32 len; /* Number of filter blocks */ >> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c >> index 649cce41e13f..5fcd19ccb41a 100644 >> --- a/kernel/bpf/core.c >> +++ b/kernel/bpf/core.c >> @@ -2619,8 +2619,7 @@ struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, >> struct >> if (fp->bpf_func) >> goto finalize; >> >> - if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || >> - bpf_prog_has_kfunc_call(fp)) >> + if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || fp->jit_required) >> jit_needed = true; >> >> if (!bpf_prog_select_interpreter(fp)) >> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c >> index 25aea4271cd0..f496b45b9da4 100644 >> --- a/kernel/bpf/verifier.c >> +++ b/kernel/bpf/verifier.c >> @@ -2765,6 +2765,8 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 >> offset) >> desc->func_model = func_model; >> sort(tab->descs, tab->nr_descs, sizeof(tab->descs[0]), >> kfunc_desc_cmp_by_id_off, NULL); >> + >> + env->prog->jit_required = 1; > > That's ok, and I think Sashiko is right about this patch. > >> return 0; >> } As discussed in another thread, I will update bpf_prog_has_kfunc_call() in v8, like this: ``` diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 25aea4271cd0..c34cc524651a 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2770,7 +2770,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 offset) bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) { - return !!prog->aux->kfunc_tab; + return prog->aux->kfunc_tab && prog->aux->kfunc_tab->nr_descs; } static int add_subprog_and_kfunc(struct bpf_verifier_env *env) ``` IIUC, there are two places to modify so far: (1) struct bpf_prog (2) bpf_prog_has_kfunc_call() If you have any more comments, please let me know. Thanks, Tiezhu ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-03 16:14 ` Tiezhu Yang @ 2026-07-04 1:57 ` KaFai Wan 2026-07-04 2:05 ` KaFai Wan 1 sibling, 0 replies; 19+ messages in thread From: KaFai Wan @ 2026-07-04 1:57 UTC (permalink / raw) To: Tiezhu Yang, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis Cc: bpf, loongarch, Leon Hwang, Puranjay Mohan, Björn Töpel On Sat, 2026-07-04 at 00:14 +0800, Tiezhu Yang wrote: > On 7/3/26 21:55, KaFai Wan wrote: > > On Thu, 2026-07-02 at 22:36 +0800, Tiezhu Yang wrote: > > > Introduce a 'jit_required' bitfield flag at the end of the > > > flags group in struct bpf_prog. This bit tracks whether a > > > program strictly requires the JIT compiler. > > > > > > Set this flag to 1 when a kfunc call is added at the end of > > > bpf_add_kfunc_call(). > > > > > > In __bpf_prog_select_runtime(), check with fp->jit_required > > > rather than bpf_prog_has_kfunc_call() to unify the logic. > > > > > > Suggested-by: Alexei Starovoitov <ast@kernel.org> > > > Suggested-by: KaFai Wan <kafai.wan@linux.dev> > > > Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn> > > > --- > > > include/linux/bpf.h | 3 ++- > > > kernel/bpf/core.c | 3 +-- > > > kernel/bpf/verifier.c | 2 ++ > > > 3 files changed, 5 insertions(+), 3 deletions(-) > > > > > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > > > index ba09795e0bfd..4e2b059d71f3 100644 > > > --- a/include/linux/bpf.h > > > +++ b/include/linux/bpf.h > > > @@ -1880,7 +1880,8 @@ struct bpf_prog { > > > call_get_func_ip:1, /* Do we call get_func_ip() */ > > > call_session_cookie:1, /* Do we call bpf_session_cookie() */ > > > tstamp_type_access:1, /* Accessed __sk_buff->tstamp_type */ > > > - sleepable:1; /* BPF program is sleepable */ > > > + sleepable:1, /* BPF program is sleepable */ > > > + jit_required:1; /* program strictly requires JIT > > > compiler > > > */ > > > > In v6 you're using 'u8 jit_required', I thought it would be 'u8 jit_required:1', so we use one > > byte > > and left 3 byte hole for future use. > > > > This version left 2 bytes hole, same as v5, but it can easily be misleading because of the u16 > > type, > > since we used 17 bits. I prefer v5, it has better readability. > > OK, I will use the previous layout in v8, like this: > > ``` > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index ba09795e0bfd..463fae6a5c33 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -1865,8 +1865,9 @@ struct bpf_prog_aux { > > struct bpf_prog { > u16 pages; /* Number of allocated pages */ > - u16 jited:1, /* Is our filter JIT'ed? */ > + u32 jited:1, /* Is our filter JIT'ed? */ > jit_requested:1,/* archs need to JIT the prog */ > + jit_required:1, /* program strictly requires JIT compiler */ > gpl_compatible:1, /* Is filter GPL compatible? */ > cb_access:1, /* Is control block accessed? */ > dst_needed:1, /* Do we need dst entry? */ > ``` > > > > > > enum bpf_prog_type type; /* Type of BPF program */ > > > enum bpf_attach_type expected_attach_type; /* For some prog types */ > > > u32 len; /* Number of filter blocks */ > > > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c > > > index 649cce41e13f..5fcd19ccb41a 100644 > > > --- a/kernel/bpf/core.c > > > +++ b/kernel/bpf/core.c > > > @@ -2619,8 +2619,7 @@ struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, > > > struct > > > if (fp->bpf_func) > > > goto finalize; > > > > > > - if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || > > > - bpf_prog_has_kfunc_call(fp)) > > > + if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || fp->jit_required) > > > jit_needed = true; > > > > > > if (!bpf_prog_select_interpreter(fp)) > > > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > > > index 25aea4271cd0..f496b45b9da4 100644 > > > --- a/kernel/bpf/verifier.c > > > +++ b/kernel/bpf/verifier.c > > > @@ -2765,6 +2765,8 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 > > > offset) > > > desc->func_model = func_model; > > > sort(tab->descs, tab->nr_descs, sizeof(tab->descs[0]), > > > kfunc_desc_cmp_by_id_off, NULL); > > > + > > > + env->prog->jit_required = 1; > > > > That's ok, and I think Sashiko is right about this patch. > > > > > return 0; > > > } > > As discussed in another thread, I will update bpf_prog_has_kfunc_call() > in v8, like this: > > ``` > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index 25aea4271cd0..c34cc524651a 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -2770,7 +2770,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env > *env, u32 func_id, u16 offset) > > bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) > { > - return !!prog->aux->kfunc_tab; > + return prog->aux->kfunc_tab && prog->aux->kfunc_tab->nr_descs; > } > > static int add_subprog_and_kfunc(struct bpf_verifier_env *env) > ``` > > IIUC, there are two places to modify so far: > (1) struct bpf_prog yes > (2) bpf_prog_has_kfunc_call() I think we can remove this func. actually, I feed your patch to dsv4-pro and gpt-5.4 yesterday, both point out the we should do this and change the log message. diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c index 12a8a4eb757f..7fb92b5fa415 100644 --- a/kernel/bpf/fixups.c +++ b/kernel/bpf/fixups.c @@ -1378,7 +1378,6 @@ int bpf_fixup_call_args(struct bpf_verifier_env *env) #ifndef CONFIG_BPF_JIT_ALWAYS_ON struct bpf_prog *prog = env->prog; struct bpf_insn *insn = prog->insnsi; - bool has_kfunc_call = bpf_prog_has_kfunc_call(prog); int depth; #endif int i, err = 0; @@ -1404,7 +1403,7 @@ int bpf_fixup_call_args(struct bpf_verifier_env *env) return err; } #ifndef CONFIG_BPF_JIT_ALWAYS_ON - if (has_kfunc_call) { + if (prog->jit_required) { verbose(env, "calling kernel functions are not allowed in non-JITed programs\n"); return -EINVAL; } I think we can change the log message for general purpose no just for kunc, so we can know why prog failed in patch#2 as you test yesterday. > > If you have any more comments, please let me know. > > Thanks, > Tiezhu > -- Thanks, KaFai ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path 2026-07-03 16:14 ` Tiezhu Yang 2026-07-04 1:57 ` KaFai Wan @ 2026-07-04 2:05 ` KaFai Wan 1 sibling, 0 replies; 19+ messages in thread From: KaFai Wan @ 2026-07-04 2:05 UTC (permalink / raw) To: Tiezhu Yang, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis Cc: bpf, loongarch, Leon Hwang, Puranjay Mohan, Björn Töpel On Sat, 2026-07-04 at 00:14 +0800, Tiezhu Yang wrote: > On 7/3/26 21:55, KaFai Wan wrote: > > On Thu, 2026-07-02 at 22:36 +0800, Tiezhu Yang wrote: > > > Introduce a 'jit_required' bitfield flag at the end of the > > > flags group in struct bpf_prog. This bit tracks whether a > > > program strictly requires the JIT compiler. > > > > > > Set this flag to 1 when a kfunc call is added at the end of > > > bpf_add_kfunc_call(). > > > > > > In __bpf_prog_select_runtime(), check with fp->jit_required > > > rather than bpf_prog_has_kfunc_call() to unify the logic. > > > > > > Suggested-by: Alexei Starovoitov <ast@kernel.org> > > > Suggested-by: KaFai Wan <kafai.wan@linux.dev> > > > Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn> > > > --- > > > include/linux/bpf.h | 3 ++- > > > kernel/bpf/core.c | 3 +-- > > > kernel/bpf/verifier.c | 2 ++ > > > 3 files changed, 5 insertions(+), 3 deletions(-) > > > > > > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > > > index ba09795e0bfd..4e2b059d71f3 100644 > > > --- a/include/linux/bpf.h > > > +++ b/include/linux/bpf.h > > > @@ -1880,7 +1880,8 @@ struct bpf_prog { > > > call_get_func_ip:1, /* Do we call get_func_ip() */ > > > call_session_cookie:1, /* Do we call bpf_session_cookie() */ > > > tstamp_type_access:1, /* Accessed __sk_buff->tstamp_type */ > > > - sleepable:1; /* BPF program is sleepable */ > > > + sleepable:1, /* BPF program is sleepable */ > > > + jit_required:1; /* program strictly requires JIT > > > compiler > > > */ > > > > In v6 you're using 'u8 jit_required', I thought it would be 'u8 jit_required:1', so we use one > > byte > > and left 3 byte hole for future use. > > > > This version left 2 bytes hole, same as v5, but it can easily be misleading because of the u16 > > type, > > since we used 17 bits. I prefer v5, it has better readability. > > OK, I will use the previous layout in v8, like this: > > ``` > diff --git a/include/linux/bpf.h b/include/linux/bpf.h > index ba09795e0bfd..463fae6a5c33 100644 > --- a/include/linux/bpf.h > +++ b/include/linux/bpf.h > @@ -1865,8 +1865,9 @@ struct bpf_prog_aux { > > struct bpf_prog { > u16 pages; /* Number of allocated pages */ > - u16 jited:1, /* Is our filter JIT'ed? */ > + u32 jited:1, /* Is our filter JIT'ed? */ > jit_requested:1,/* archs need to JIT the prog */ > + jit_required:1, /* program strictly requires JIT compiler */ > gpl_compatible:1, /* Is filter GPL compatible? */ > cb_access:1, /* Is control block accessed? */ > dst_needed:1, /* Do we need dst entry? */ > ``` > > > > > > enum bpf_prog_type type; /* Type of BPF program */ > > > enum bpf_attach_type expected_attach_type; /* For some prog types */ > > > u32 len; /* Number of filter blocks */ > > > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c > > > index 649cce41e13f..5fcd19ccb41a 100644 > > > --- a/kernel/bpf/core.c > > > +++ b/kernel/bpf/core.c > > > @@ -2619,8 +2619,7 @@ struct bpf_prog *__bpf_prog_select_runtime(struct bpf_verifier_env *env, > > > struct > > > if (fp->bpf_func) > > > goto finalize; > > > > > > - if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || > > > - bpf_prog_has_kfunc_call(fp)) > > > + if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) || fp->jit_required) > > > jit_needed = true; > > > > > > if (!bpf_prog_select_interpreter(fp)) > > > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > > > index 25aea4271cd0..f496b45b9da4 100644 > > > --- a/kernel/bpf/verifier.c > > > +++ b/kernel/bpf/verifier.c > > > @@ -2765,6 +2765,8 @@ int bpf_add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, u16 > > > offset) > > > desc->func_model = func_model; > > > sort(tab->descs, tab->nr_descs, sizeof(tab->descs[0]), > > > kfunc_desc_cmp_by_id_off, NULL); > > > + > > > + env->prog->jit_required = 1; > > > > That's ok, and I think Sashiko is right about this patch. > > > > > return 0; > > > } > > As discussed in another thread, I will update bpf_prog_has_kfunc_call() > in v8, like this: > > ``` > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > index 25aea4271cd0..c34cc524651a 100644 > --- a/kernel/bpf/verifier.c > +++ b/kernel/bpf/verifier.c > @@ -2770,7 +2770,7 @@ int bpf_add_kfunc_call(struct bpf_verifier_env > *env, u32 func_id, u16 offset) > > bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog) > { > - return !!prog->aux->kfunc_tab; > + return prog->aux->kfunc_tab && prog->aux->kfunc_tab->nr_descs; !!prog->aux->kfunc_tab works fine when bpf_prog_has_kfunc_call() called currently, no need to check prog->aux->kfunc_tab->nr_descs, see other thread. > } > > static int add_subprog_and_kfunc(struct bpf_verifier_env *env) > ``` > > IIUC, there are two places to modify so far: > (1) struct bpf_prog > (2) bpf_prog_has_kfunc_call() > > If you have any more comments, please let me know. > > Thanks, > Tiezhu > -- Thanks, KaFai ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH bpf-next v7 2/2] bpf: Reject programs with inlined helpers if JIT is unavailable 2026-07-02 14:36 [PATCH bpf-next v7 0/2] Introduce jit_required to prevent a kernel panic Tiezhu Yang 2026-07-02 14:36 ` [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path Tiezhu Yang @ 2026-07-02 14:36 ` Tiezhu Yang 2026-07-02 14:57 ` sashiko-bot 1 sibling, 1 reply; 19+ messages in thread From: Tiezhu Yang @ 2026-07-02 14:36 UTC (permalink / raw) To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, KaFai Wan Cc: bpf, loongarch, Leon Hwang, Puranjay Mohan, Björn Töpel When an architecture implements bpf_jit_inlines_helper_call() (such as LoongArch, ARM64, PowerPC, and RISC-V), the verifier skips rewriting the helper call offset (insn->imm) during the bpf_do_misc_fixups() phase, because the helper is expected to be inlined by the JIT compiler. As a result, insn->imm remains as the raw helper enum ID. However, if JIT is disabled at runtime (net.core.bpf_jit_enable=0) or if the JIT compilation later dynamically fails (e.g., due to OOM), the core BPF subsystem falls back to the BPF interpreter. When the interpreter executes (__bpf_call_base + insn->imm) with the unpatched raw helper ID, it jumps into an unaligned invalid address space, triggering an instruction alignment fault or a memory access panic. Fix this by setting 'jit_required' to 1 when helper call rewriting is skipped for JIT inlining. During runtime selection, if JIT compilation is not available, explicitly reject loading with -ENOTSUPP based on this flag to safely prevent the kernel panic. Fixes: 2ddec2c80b44 ("riscv, bpf: inline bpf_get_smp_processor_id()") Suggested-by: Alexei Starovoitov <ast@kernel.org> Suggested-by: KaFai Wan <kafai.wan@linux.dev> Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn> --- kernel/bpf/fixups.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c index 12a8a4eb757f..94e0457a0aa3 100644 --- a/kernel/bpf/fixups.c +++ b/kernel/bpf/fixups.c @@ -1841,8 +1841,10 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env) } /* Skip inlining the helper call if the JIT does it. */ - if (bpf_jit_inlines_helper_call(insn->imm)) + if (bpf_jit_inlines_helper_call(insn->imm)) { + prog->jit_required = 1; goto next_insn; + } if (insn->imm == BPF_FUNC_get_route_realm) prog->dst_needed = 1; -- 2.42.0 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 2/2] bpf: Reject programs with inlined helpers if JIT is unavailable 2026-07-02 14:36 ` [PATCH bpf-next v7 2/2] bpf: Reject programs with inlined helpers if JIT is unavailable Tiezhu Yang @ 2026-07-02 14:57 ` sashiko-bot 2026-07-03 4:14 ` Tiezhu Yang 0 siblings, 1 reply; 19+ messages in thread From: sashiko-bot @ 2026-07-02 14:57 UTC (permalink / raw) To: Tiezhu Yang; +Cc: bpf Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] The patch prevents loading BPF programs that use JIT-inlined helpers (e.g., `bpf_get_smp_processor_id`) when the BPF JIT is explicitly disabled at load time (`net.core.bpf_jit_enable=0`). -- commit 01713d8606e656f4dadefe493f371f4c861d842b Author: Tiezhu Yang <yangtiezhu@loongson.cn> bpf: Reject programs with inlined helpers if JIT is unavailable This patch sets the jit_required flag to 1 when a BPF program uses helpers that are expected to be inlined by the JIT compiler. This prevents a kernel panic in the BPF interpreter by rejecting the program with -ENOTSUPP if JIT compilation is unavailable at runtime. > diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c > index 12a8a4eb757f1..94e0457a0aa33 100644 > --- a/kernel/bpf/fixups.c > +++ b/kernel/bpf/fixups.c > @@ -1841,8 +1841,10 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env) > } > > /* Skip inlining the helper call if the JIT does it. */ > - if (bpf_jit_inlines_helper_call(insn->imm)) > + if (bpf_jit_inlines_helper_call(insn->imm)) { > + prog->jit_required = 1; > goto next_insn; > + } [Severity: High] While this correctly prevents the interpreter panic, does this unconditionally reject valid BPF programs when the JIT is explicitly disabled at load time (e.g., net.core.bpf_jit_enable=0)? If this block checked prog->jit_requested before skipping the fixup and setting jit_required, wouldn't the verifier properly patch the instruction when JIT is disabled, allowing the program to execute successfully in the interpreter? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260702143656.28845-1-yangtiezhu@loongson.cn?part=2 ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH bpf-next v7 2/2] bpf: Reject programs with inlined helpers if JIT is unavailable 2026-07-02 14:57 ` sashiko-bot @ 2026-07-03 4:14 ` Tiezhu Yang 0 siblings, 0 replies; 19+ messages in thread From: Tiezhu Yang @ 2026-07-03 4:14 UTC (permalink / raw) To: sashiko-reviews; +Cc: bpf, Alexei Starovoitov, KaFai Wan On 2026/7/2 下午10:57, sashiko-bot@kernel.org wrote: > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > - [High] The patch prevents loading BPF programs that use JIT-inlined helpers (e.g., `bpf_get_smp_processor_id`) when the BPF JIT is explicitly disabled at load time (`net.core.bpf_jit_enable=0`). > -- > > commit 01713d8606e656f4dadefe493f371f4c861d842b > Author: Tiezhu Yang <yangtiezhu@loongson.cn> > > bpf: Reject programs with inlined helpers if JIT is unavailable > > This patch sets the jit_required flag to 1 when a BPF program uses helpers > that are expected to be inlined by the JIT compiler. This prevents a kernel > panic in the BPF interpreter by rejecting the program with -ENOTSUPP if > JIT compilation is unavailable at runtime. > >> diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c >> index 12a8a4eb757f1..94e0457a0aa33 100644 >> --- a/kernel/bpf/fixups.c >> +++ b/kernel/bpf/fixups.c >> @@ -1841,8 +1841,10 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env) >> } >> >> /* Skip inlining the helper call if the JIT does it. */ >> - if (bpf_jit_inlines_helper_call(insn->imm)) >> + if (bpf_jit_inlines_helper_call(insn->imm)) { >> + prog->jit_required = 1; >> goto next_insn; >> + } > > [Severity: High] > While this correctly prevents the interpreter panic, does this unconditionally > reject valid BPF programs when the JIT is explicitly disabled at load time > (e.g., net.core.bpf_jit_enable=0)? Yes. > If this block checked prog->jit_requested before skipping the fixup and > setting jit_required, wouldn't the verifier properly patch the instruction > when JIT is disabled, allowing the program to execute successfully in the > interpreter? No, this was already explored in earlier version (v4), but it was explicitly rejected by the BPF maintainer. If JIT is unavailable, rejecting the program load with -ENOTSUPP is the intended design. Thanks, Tiezhu ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2026-07-04 3:24 UTC | newest] Thread overview: 19+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-02 14:36 [PATCH bpf-next v7 0/2] Introduce jit_required to prevent a kernel panic Tiezhu Yang 2026-07-02 14:36 ` [PATCH bpf-next v7 1/2] bpf: Introduce jit_required flag and refactor kfunc path Tiezhu Yang 2026-07-02 14:58 ` sashiko-bot 2026-07-03 2:57 ` Tiezhu Yang 2026-07-03 5:24 ` Leon Hwang 2026-07-03 6:59 ` Tiezhu Yang 2026-07-03 14:14 ` Leon Hwang 2026-07-03 15:53 ` Tiezhu Yang 2026-07-04 1:17 ` KaFai Wan 2026-07-03 13:51 ` KaFai Wan 2026-07-03 15:56 ` Tiezhu Yang 2026-07-04 3:23 ` KaFai Wan 2026-07-03 13:55 ` KaFai Wan 2026-07-03 16:14 ` Tiezhu Yang 2026-07-04 1:57 ` KaFai Wan 2026-07-04 2:05 ` KaFai Wan 2026-07-02 14:36 ` [PATCH bpf-next v7 2/2] bpf: Reject programs with inlined helpers if JIT is unavailable Tiezhu Yang 2026-07-02 14:57 ` sashiko-bot 2026-07-03 4:14 ` Tiezhu Yang
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox