Re: [PATCH bpf-next v3] bpf: arm64: Fix panic due to missing BTI at indirect jump targets
From: Xu Kuohai
Date: Wed Dec 31 2025 - 04:22:18 EST
On 12/31/2025 3:06 PM, Anton Protopopov wrote:
On Wed, Dec 31, 2025 at 7:47 AM Xu Kuohai <xukuohai@xxxxxxxxxxxxxxx> wrote:
On 12/31/2025 10:16 AM, Alexei Starovoitov wrote:
On Tue, Dec 30, 2025 at 6:05 PM Xu Kuohai <xukuohai@xxxxxxxxxxxxxxx> wrote:
On 12/31/2025 2:20 AM, Alexei Starovoitov wrote:
On Fri, Dec 26, 2025 at 11:49 PM Xu Kuohai <xukuohai@xxxxxxxxxxxxxxx> wrote:
From: Xu Kuohai <xukuohai@xxxxxxxxxx>
When BTI is enabled, the indirect jump selftest triggers BTI exception:
Internal error: Oops - BTI: 0000000036000003 [#1] SMP
...
Call trace:
bpf_prog_2e5f1c71c13ac3e0_big_jump_table+0x54/0xf8 (P)
bpf_prog_run_pin_on_cpu+0x140/0x464
bpf_prog_test_run_syscall+0x274/0x3ac
bpf_prog_test_run+0x224/0x2b0
__sys_bpf+0x4cc/0x5c8
__arm64_sys_bpf+0x7c/0x94
invoke_syscall+0x78/0x20c
el0_svc_common+0x11c/0x1c0
do_el0_svc+0x48/0x58
el0_svc+0x54/0x19c
el0t_64_sync_handler+0x84/0x12c
el0t_64_sync+0x198/0x19c
This happens because no BTI instruction is generated by the JIT for
indirect jump targets.
Fix it by emitting BTI instruction for every possible indirect jump
targets when BTI is enabled. The targets are identified by traversing
all instruction arrays of jump table type used by the BPF program,
since indirect jump targets can only be read from instruction arrays
of jump table type.
earlier you said:
As Anton noted, even though jump tables are currently the only type
of instruction array, users may still create insn_arrays that are not
used as jump tables. In such cases, there is no need to emit BTIs.
yes, but it's not worth it to make this micro optimization in JIT.
If it's in insn_array just emit BTI unconditionally.
No need to do this filtering.
Hmm, that is what the v1 version does. Please take a look. If it’s okay,
I’ll resend a rebased version.
v1: https://lore.kernel.org/bpf/20251127140318.3944249-1-xukuohai@xxxxxxxxxxxxxxx/
I don't think you need bitmap and bpf_prog_collect_indirect_targets().
Just look up each insn in the insn_array one at a time.
It's slower, but array is sorted, so binary search should work.
No, an insn_array is not always sorted, as its ordering depends on how
it is initialized.
For example, with the following change to the selftest:
--- a/tools/testing/selftests/bpf/prog_tests/bpf_insn_array.c
+++ b/tools/testing/selftests/bpf/prog_tests/bpf_insn_array.c
@@ -75,7 +75,7 @@ static void check_one_to_one_mapping(void)
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
};
- __u32 map_in[] = {0, 1, 2, 3, 4, 5};
+ __u32 map_in[] = {0, 3, 1, 2, 4, 5};
__u32 map_out[] = {0, 1, 2, 3, 4, 5};
__check_success(insns, ARRAY_SIZE(insns), map_in, map_out);
the selftest will create an unsorted map, as shown below:
# bpftool m d i 74
key: 00 00 00 00 value: 00 00 00 00 00 00 00 00 24 00 00 00 00 00 00 00
key: 01 00 00 00 value: 03 00 00 00 03 00 00 00 30 00 00 00 00 00 00 00
key: 02 00 00 00 value: 01 00 00 00 01 00 00 00 28 00 00 00 00 00 00 00
key: 03 00 00 00 value: 02 00 00 00 02 00 00 00 2c 00 00 00 00 00 00 00
key: 04 00 00 00 value: 04 00 00 00 04 00 00 00 34 00 00 00 00 00 00 00
key: 05 00 00 00 value: 05 00 00 00 05 00 00 00 38 00 00 00 00 00 00 00
Found 6 elements
Yes, it is not always sorted (jump tables aren't guaranteed to be
sorted or have unique values).
To get rid of bpf_prog_collect_indirect_targets() in internal API,
this is possible to just implement this inside arm JIT. If later it is
needed in more cases, it can be generalized.
Also, how bad is this to generate BTI instructions not only for jump
targets (say, for all instructions in the program)? If this is ok-ish
(this is a really rare condition now), then `bool is_jump_table` might
be dropped for now. (I will add similar code when add static keys and
indirect calls such that they aren't counted for BTI.)
IIUC, in practice insn_array usually contains only a few elements, so using
a simple linear search should be sufficient.
In corner cases, such as when all instructions are included in an insn_array
but only a few are actually used as indirect jump targets, even is_jump_table
would not prevent BTI from being jited for non-jump-target instructions. To
completely avoid this, more precise information about which instructions are
actually used as indirect jump targets would be required.