On Wed, Nov 22, 2023 at 12:15:17PM +0100, Peter Zijlstra wrote: > Ah, so normally the __cfi_foo symbol would catch those, lemme see what I > can do here. I have the below delta (untested etc..), does that look about right? --- --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -845,19 +845,24 @@ enum cfi_mode cfi_mode __ro_after_init = #ifdef CONFIG_CFI_CLANG struct bpf_insn; -extern unsigned int bpf_func_proto(const void *ctx, - const struct bpf_insn *insn); +/* Must match bpf_func_t / DEFINE_BPF_PROG_RUN() */ +extern unsigned int __bpf_prog_runX(const void *ctx, + const struct bpf_insn *insn); -__ADDRESSABLE(bpf_func_proto); +/* + * Force a reference to the external symbol so the compiler generates + * __kcfi_typid. + */ +__ADDRESSABLE(__bpf_prog_runX); -/* u32 __ro_after_init cfi_bpf_hash = __kcfi_typeid_bpf_func_proto */ +/* u32 __ro_after_init cfi_bpf_hash = __kcfi_typeid___bpf_prog_runX */ asm ( " .pushsection .data..ro_after_init,\"aw\",@progbits \n" " .type cfi_bpf_hash,@object \n" " .globl cfi_bpf_hash \n" " .p2align 2, 0x0 \n" "cfi_bpf_hash: \n" -" .long __kcfi_typeid_bpf_func_proto \n" +" .long __kcfi_typeid___bpf_prog_runX \n" " .size cfi_bpf_hash, 4 \n" " .popsection \n" ); --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -308,15 +308,20 @@ static void pop_callee_regs(u8 **pprog, *pprog = prog; } +/* + * Emit the various CFI preambles, see the large comment about FineIBT + * in arch/x86/kernel/alternative.c + */ + static int emit_fineibt(u8 **pprog) { u8 *prog = *pprog; EMIT_ENDBR(); - EMIT3_off32(0x41, 0x81, 0xea, cfi_bpf_hash); - EMIT2(0x74, 0x07); - EMIT2(0x0f, 0x0b); - EMIT1(0x90); + EMIT3_off32(0x41, 0x81, 0xea, cfi_bpf_hash); /* subl $hash, %r10d */ + EMIT2(0x74, 0x07); /* jz.d8 +7 */ + EMIT2(0x0f, 0x0b); /* ud2 */ + EMIT1(0x90); /* nop */ EMIT_ENDBR_POISON(); *pprog = prog; @@ -328,7 +333,7 @@ static int emit_kcfi(u8 **pprog) u8 *prog = *pprog; int offset = 5; - EMIT1_off32(0xb8, cfi_bpf_hash); + EMIT1_off32(0xb8, cfi_bpf_hash); /* movl $hash, %eax */ #ifdef CONFIG_CALL_PADDING EMIT1(0x90); EMIT1(0x90); @@ -3009,6 +3014,10 @@ struct bpf_prog *bpf_int_jit_compile(str jit_data->header = header; jit_data->rw_header = rw_header; } + /* + * ctx.prog_offset is used when CFI preambles put code *before* + * the function. See emit_cfi(). + */ prog->bpf_func = (void *)image + ctx.prog_offset; prog->jited = 1; prog->jited_len = proglen - ctx.prog_offset; // XXX? --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1431,6 +1431,9 @@ struct bpf_prog_aux { struct bpf_kfunc_desc_tab *kfunc_tab; struct bpf_kfunc_btf_tab *kfunc_btf_tab; u32 size_poke_tab; +#ifdef CONFIG_FINEIBT + struct bpf_ksym ksym_prefix; +#endif struct bpf_ksym ksym; const struct bpf_prog_ops *ops; struct bpf_map **used_maps; --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -683,6 +683,23 @@ void bpf_prog_kallsyms_add(struct bpf_pr fp->aux->ksym.prog = true; bpf_ksym_add(&fp->aux->ksym); + +#ifdef CONFIG_FINEIBT + /* + * When FineIBT, code in the __cfi_foo() symbols can get executed + * and hence unwinder needs help. + */ + if (cfi_mode != CFI_FINEIBT) + return; + + snprintf(fp->aux->ksym_prefix.name, KSYM_NAME_LEN, + "__cfi_%s", fp->aux->ksym.name); + + prog->aux->ksym_prefix.start = (unsigned long) prog->bpf_func - 16; + prog->aux->ksym_prefix.end = (unsigned long) prog->bpf_func; + + bpf_ksym_add(&fp->aux->ksym_prefix); +#endif } void bpf_prog_kallsyms_del(struct bpf_prog *fp)