* [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
* [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 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 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
* 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 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-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 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 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 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 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 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
* 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
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