Skip to content

Commit 9a0e89d

Browse files
Xu KuohaiAlexei Starovoitov
authored andcommitted
bpf, x86: Emit ENDBR for indirect jump targets
On CPUs that support CET/IBT, the indirect jump selftest triggers a kernel panic because the indirect jump targets lack ENDBR instructions. To fix it, emit an ENDBR instruction to each indirect jump target. Since the ENDBR instruction shifts the position of original jited instructions, fix the instruction address calculation wherever the addresses are used. For reference, below is a sample panic log. Missing ENDBR: bpf_prog_2e5f1c71c13ac3e0_big_jump_table+0x97/0xe1 ------------[ cut here ]------------ kernel BUG at arch/x86/kernel/cet.c:133! Oops: invalid opcode: 0000 [#1] SMP NOPTI ... ? 0xffffffffc00fb258 ? bpf_prog_2e5f1c71c13ac3e0_big_jump_table+0x97/0xe1 bpf_prog_test_run_syscall+0x110/0x2f0 ? fdget+0xba/0xe0 __sys_bpf+0xe4b/0x2590 ? __kmalloc_node_track_caller_noprof+0x1c7/0x680 ? bpf_prog_test_run_syscall+0x215/0x2f0 __x64_sys_bpf+0x21/0x30 do_syscall_64+0x85/0x620 ? bpf_prog_test_run_syscall+0x1e2/0x2f0 Fixes: 493d9e0 ("bpf, x86: add support for indirect jumps") Reviewed-by: Anton Protopopov <a.s.protopopov@gmail.com> # v8 Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com> # v12 Acked-by: Leon Hwang <leon.hwang@linux.dev> Signed-off-by: Xu Kuohai <xukuohai@huawei.com> Link: https://lore.kernel.org/r/20260416064341.151802-5-xukuohai@huaweicloud.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 07ae6c1 commit 9a0e89d

1 file changed

Lines changed: 15 additions & 13 deletions

File tree

arch/x86/net/bpf_jit_comp.c

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
5858
#define EMIT_ENDBR() EMIT(gen_endbr(), 4)
5959
#define EMIT_ENDBR_POISON() EMIT(gen_endbr_poison(), 4)
6060
#else
61-
#define EMIT_ENDBR()
62-
#define EMIT_ENDBR_POISON()
61+
#define EMIT_ENDBR() do { } while (0)
62+
#define EMIT_ENDBR_POISON() do { } while (0)
6363
#endif
6464

6565
static bool is_imm8(int value)
@@ -1649,8 +1649,8 @@ static int emit_spectre_bhb_barrier(u8 **pprog, u8 *ip,
16491649
return 0;
16501650
}
16511651

1652-
static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image,
1653-
int oldproglen, struct jit_context *ctx, bool jmp_padding)
1652+
static int do_jit(struct bpf_verifier_env *env, struct bpf_prog *bpf_prog, int *addrs, u8 *image,
1653+
u8 *rw_image, int oldproglen, struct jit_context *ctx, bool jmp_padding)
16541654
{
16551655
bool tail_call_reachable = bpf_prog->aux->tail_call_reachable;
16561656
struct bpf_insn *insn = bpf_prog->insnsi;
@@ -1663,7 +1663,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
16631663
void __percpu *priv_stack_ptr;
16641664
int i, excnt = 0;
16651665
int ilen, proglen = 0;
1666-
u8 *prog = temp;
1666+
u8 *ip, *prog = temp;
16671667
u32 stack_depth;
16681668
int err;
16691669

@@ -1734,6 +1734,11 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
17341734
dst_reg = X86_REG_R9;
17351735
}
17361736

1737+
if (bpf_insn_is_indirect_target(env, bpf_prog, i - 1))
1738+
EMIT_ENDBR();
1739+
1740+
ip = image + addrs[i - 1] + (prog - temp);
1741+
17371742
switch (insn->code) {
17381743
/* ALU */
17391744
case BPF_ALU | BPF_ADD | BPF_X:
@@ -2440,8 +2445,6 @@ st: if (is_imm8(insn->off))
24402445

24412446
/* call */
24422447
case BPF_JMP | BPF_CALL: {
2443-
u8 *ip = image + addrs[i - 1];
2444-
24452448
func = (u8 *) __bpf_call_base + imm32;
24462449
if (src_reg == BPF_PSEUDO_CALL && tail_call_reachable) {
24472450
LOAD_TAIL_CALL_CNT_PTR(stack_depth);
@@ -2465,7 +2468,8 @@ st: if (is_imm8(insn->off))
24652468
if (imm32)
24662469
emit_bpf_tail_call_direct(bpf_prog,
24672470
&bpf_prog->aux->poke_tab[imm32 - 1],
2468-
&prog, image + addrs[i - 1],
2471+
&prog,
2472+
ip,
24692473
callee_regs_used,
24702474
stack_depth,
24712475
ctx);
@@ -2474,7 +2478,7 @@ st: if (is_imm8(insn->off))
24742478
&prog,
24752479
callee_regs_used,
24762480
stack_depth,
2477-
image + addrs[i - 1],
2481+
ip,
24782482
ctx);
24792483
break;
24802484

@@ -2639,7 +2643,7 @@ st: if (is_imm8(insn->off))
26392643
break;
26402644

26412645
case BPF_JMP | BPF_JA | BPF_X:
2642-
emit_indirect_jump(&prog, insn->dst_reg, image + addrs[i - 1]);
2646+
emit_indirect_jump(&prog, insn->dst_reg, ip);
26432647
break;
26442648
case BPF_JMP | BPF_JA:
26452649
case BPF_JMP32 | BPF_JA:
@@ -2729,8 +2733,6 @@ st: if (is_imm8(insn->off))
27292733
ctx->cleanup_addr = proglen;
27302734
if (bpf_prog_was_classic(bpf_prog) &&
27312735
!ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN)) {
2732-
u8 *ip = image + addrs[i - 1];
2733-
27342736
if (emit_spectre_bhb_barrier(&prog, ip, bpf_prog))
27352737
return -EINVAL;
27362738
}
@@ -3791,7 +3793,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
37913793
for (pass = 0; pass < MAX_PASSES || image; pass++) {
37923794
if (!padding && pass >= PADDING_PASSES)
37933795
padding = true;
3794-
proglen = do_jit(prog, addrs, image, rw_image, oldproglen, &ctx, padding);
3796+
proglen = do_jit(env, prog, addrs, image, rw_image, oldproglen, &ctx, padding);
37953797
if (proglen <= 0) {
37963798
out_image:
37973799
image = NULL;

0 commit comments

Comments
 (0)