From 34746b5a84ec37c0ea2bf6808c65c5ed8790eb51 Mon Sep 17 00:00:00 2001 From: Leon Hwang Date: Wed, 15 Jul 2026 22:11:20 +0800 Subject: [PATCH 1/3] bpf: Disallow interpreter fallback for arena-related insns Since the interpreter does not support the arena-related insns, interpreter fallback should not be allowed for these insns in core.c::__bpf_prog_select_runtime(). Currently, when the interpreter executes the arena ST/LDX/STX insns, it would hit the BUG_ON() in ___bpf_prog_run() at run time. [ 2.579196] BPF interpreter: unknown opcode a2 (imm: 0x0) [ 2.579998] ------------[ cut here ]------------ [ 2.580652] kernel BUG at kernel/bpf/core.c:2349! [ 2.581314] Oops: invalid opcode: 0000 [#1] SMP PTI Set jit_required as true when arena map is used in the prog to disallow interpreter fallback for arena-related insns. Fixes: 6082b6c328b5 ("bpf: Recognize addr_space_cast instruction in the verifier.") Signed-off-by: Leon Hwang Link: https://lore.kernel.org/bpf/20260715141122.15783-2-leon.hwang@linux.dev Signed-off-by: Kumar Kartikeya Dwivedi --- kernel/bpf/verifier.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 4446f0bde88b..2d323f13da19 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -17887,6 +17887,7 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env, return -EOPNOTSUPP; } env->prog->aux->arena = (void *)map; + env->prog->jit_required = true; if (!bpf_arena_get_user_vm_start(env->prog->aux->arena)) { verbose(env, "arena's user address must be set via map_extra or mmap()\n"); return -EINVAL; From 905f716362e1186c1a23447ca279e6d21f795cdb Mon Sep 17 00:00:00 2001 From: Leon Hwang Date: Wed, 15 Jul 2026 22:11:21 +0800 Subject: [PATCH 2/3] bpf: Disallow interpreter fallback for gotox insn The interpreter does not recognize the BPF_JMP|BPF_JA|BPF_X insn, which is used for insn_array map. Thereafter, it would hit the BUG_ON() in ___bpf_prog_run() at run time. [ 2.563726] BPF interpreter: unknown opcode 0d (imm: 0x0) [ 2.564557] ------------[ cut here ]------------ [ 2.565206] kernel BUG at kernel/bpf/core.c:2349! [ 2.565882] Oops: invalid opcode: 0000 [#1] SMP PTI Set jit_required as true when insn_array map is used in the prog in order to disallow interpreter fallback for gotox insn in core.c::__bpf_prog_select_runtime(). Fixes: 493d9e0d6083 ("bpf, x86: add support for indirect jumps") Signed-off-by: Leon Hwang Link: https://lore.kernel.org/bpf/20260715141122.15783-3-leon.hwang@linux.dev Signed-off-by: Kumar Kartikeya Dwivedi --- kernel/bpf/verifier.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 2d323f13da19..52be0a118cce 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -17941,6 +17941,7 @@ static int __add_used_map(struct bpf_verifier_env *env, struct bpf_map *map) return err; } env->insn_array_maps[env->insn_array_map_cnt++] = map; + env->prog->jit_required = true; } return env->used_map_cnt - 1; From 7a0855e73757ee9cf25ba635a1c735018ecba742 Mon Sep 17 00:00:00 2001 From: Leon Hwang Date: Wed, 15 Jul 2026 22:11:22 +0800 Subject: [PATCH 3/3] bpf: Disallow interpreter fallback for BPF_ADDR_PERCPU insn The BPF_MOV64_PERCPU_REG insn requires JIT to emit native code to for 'dst_reg = src_reg + '. However, the interpreter ignores the 'off' at its ALU64_MOV_X label. The 'off' indicates the insn is BPF_MOV64_PERCPU_REG insn. Then, when the interpreter loads memory from the register, it will hit a page fault. [ 2.545572] BUG: unable to handle page fault for address: ffffffffacaaf034 [ 2.546485] #PF: supervisor read access in kernel mode [ 2.547167] #PF: error_code(0x0000) - not-present page [ 2.547850] PGD 134e63067 P4D 134e63067 PUD 134e64063 PMD 10021c063 PTE 800ffffeca550062 [ 2.548912] Oops: Oops: 0000 [#1] SMP PTI Set jit_required as true in order to disallow interpreter fallback in core.c::__bpf_prog_select_runtime(), if any BPF_ADDR_PERCPU insn is patched to the prog. BTW, rename the helper bpf_map_supports_cpu_flags() to bpf_map_is_percpu_map(). Fixes: 7bdbf7446305 ("bpf: add special internal-only MOV instruction to resolve per-CPU addrs") Signed-off-by: Leon Hwang Link: https://lore.kernel.org/bpf/20260715141122.15783-4-leon.hwang@linux.dev Signed-off-by: Kumar Kartikeya Dwivedi --- include/linux/bpf.h | 4 ++-- kernel/bpf/fixups.c | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 31181e0c2b80..d9542127dfdf 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -4163,7 +4163,7 @@ bpf_prog_update_insn_ptrs(struct bpf_prog *prog, u32 *offsets, void *image) } #endif -static inline bool bpf_map_supports_cpu_flags(enum bpf_map_type map_type) +static inline bool bpf_map_is_percpu_map(enum bpf_map_type map_type) { switch (map_type) { case BPF_MAP_TYPE_PERCPU_ARRAY: @@ -4190,7 +4190,7 @@ static inline int bpf_map_check_op_flags(struct bpf_map *map, u64 flags, u64 all return -EINVAL; if (flags & (BPF_F_CPU | BPF_F_ALL_CPUS)) { - if (!bpf_map_supports_cpu_flags(map->map_type)) + if (!bpf_map_is_percpu_map(map->map_type)) return -EINVAL; if ((flags & BPF_F_CPU) && (flags & BPF_F_ALL_CPUS)) return -EINVAL; diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c index d3be972714b2..a0bddada7964 100644 --- a/kernel/bpf/fixups.c +++ b/kernel/bpf/fixups.c @@ -2008,6 +2008,9 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env) return -EFAULT; } + if (bpf_map_is_percpu_map(map_ptr->map_type)) + prog->jit_required = true; + new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt); if (!new_prog) @@ -2112,6 +2115,7 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env) * way, it's fine to back out this inlining logic */ #ifdef CONFIG_SMP + prog->jit_required = true; insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, (u32)(unsigned long)&cpu_number); insn_buf[1] = BPF_MOV64_PERCPU_REG(BPF_REG_0, BPF_REG_0); insn_buf[2] = BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 0); @@ -2133,6 +2137,7 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env) /* Implement bpf_get_current_task() and bpf_get_current_task_btf() inline. */ if ((insn->imm == BPF_FUNC_get_current_task || insn->imm == BPF_FUNC_get_current_task_btf) && bpf_verifier_inlines_helper_call(env, insn->imm)) { + prog->jit_required = true; insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, (u32)(unsigned long)¤t_task); insn_buf[1] = BPF_MOV64_PERCPU_REG(BPF_REG_0, BPF_REG_0); insn_buf[2] = BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0);