Messages in this thread Patch in this message | | | Date | Fri, 25 Feb 2022 16:28:32 +0100 | From | Peter Zijlstra <> | Subject | Re: [PATCH v2 00/39] x86: Kernel IBT |
| |
On Thu, Feb 24, 2022 at 12:26:02PM -0800, Josh Poimboeuf wrote:
> Bricked my SPR: > > [ 21.602888] jump_label: Fatal kernel bug, unexpected op at sched_clock_stable+0x4/0x20 [0000000074a0db20] (eb 06 b8 01 00 != eb 0a 00 00 00)) size:2 type:0
> ffffffff81120a70 <sched_clock_stable>: > ffffffff81120a70: f3 0f 1e fa endbr64 > ffffffff81120a74: eb 06 jmp ffffffff81120a7c <sched_clock_stable+0xc> > ffffffff81120a76: b8 01 00 00 00 mov $0x1,%eax > ffffffff81120a7b: c3 retq > ffffffff81120a7c: f3 0f 1e fa endbr64 > ffffffff81120a80: 31 c0 xor %eax,%eax > ffffffff81120a82: c3 retq > ffffffff81120a83: 66 66 2e 0f 1f 84 00 data16 nopw %cs:0x0(%rax,%rax,1) > ffffffff81120a8a: 00 00 00 00 > ffffffff81120a8e: 66 90 xchg %ax,%ax
This is due to you having a very old (and arguably buggy) compiler :-( I can reproduce with gcc-8.4 and gcc-9.4, my gcc-10.3 compiler no longer generates daft code like that, nor do any later.
That said, I can fix objtool to also re-write jumps to in-the-middle ENDBR like this, but then I do get a bunch of:
OBJTOOL vmlinux.o vmlinux.o: warning: objtool: displacement doesn't fit vmlinux.o: warning: objtool: ep_insert()+0xbc5: Direct IMM jump to ENDBR; cannot fix vmlinux.o: warning: objtool: displacement doesn't fit vmlinux.o: warning: objtool: configfs_depend_prep()+0x76: Direct IMM jump to ENDBR; cannot fix vmlinux.o: warning: objtool: displacement doesn't fit vmlinux.o: warning: objtool: request_key_and_link()+0x17b: Direct IMM jump to ENDBR; cannot fix vmlinux.o: warning: objtool: displacement doesn't fit vmlinux.o: warning: objtool: blk_mq_poll()+0x2e0: Direct IMM jump to ENDBR; cannot fix
The alternative is only skipping endbr at +0 I suppose, lemme go try that with the brand spanking new skip_endbr() function.
Yep,.. that seems to cure things. It noaw boats when build with old crappy compilers too.
--- a/arch/x86/include/asm/ibt.h +++ b/arch/x86/include/asm/ibt.h @@ -47,6 +47,8 @@ static inline bool is_endbr(unsigned int return val == gen_endbr(); } +extern void *skip_endbr(void *); + extern __noendbr u64 ibt_save(void); extern __noendbr void ibt_restore(u64 save); @@ -71,6 +73,7 @@ extern __noendbr void ibt_restore(u64 sa #define __noendbr static inline bool is_endbr(unsigned int val) { return false; } +static inline void *skip_endbr(void *addr) { return addr; } static inline u64 ibt_save(void) { return 0; } static inline void ibt_restore(u64 save) { } --- a/arch/x86/include/asm/text-patching.h +++ b/arch/x86/include/asm/text-patching.h @@ -112,10 +112,7 @@ void __text_gen_insn(void *buf, u8 opcod OPTIMIZER_HIDE_VAR(addr); OPTIMIZER_HIDE_VAR(dest); -#ifdef CONFIG_X86_KERNEL_IBT - if (is_endbr(*(u32 *)dest)) - dest += 4; -#endif + dest = skip_endbr((void *)dest); insn->opcode = opcode; --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -620,6 +620,19 @@ __noendbr void ibt_restore(u64 save) } } + +void *skip_endbr(void *addr) +{ + unsigned long size, offset; + + if (is_endbr(*(unsigned int *)addr) && + kallsyms_lookup_size_offset((unsigned long)addr, &size, &offset) && + !offset) + addr += 4; + + return addr; +} + #endif static __always_inline void setup_cet(struct cpuinfo_x86 *c) @@ -636,7 +649,10 @@ static __always_inline void setup_cet(st if (!ibt_selftest()) { pr_err("IBT selftest: Failed!\n"); setup_clear_cpu_cap(X86_FEATURE_IBT); + return; } + + pr_info("CET detected: Indirect Branch Tracking enabled\n"); } __noendbr void cet_disable(void) --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -350,18 +350,12 @@ static int __bpf_arch_text_poke(void *ip u8 *prog; int ret; -#ifdef CONFIG_X86_KERNEL_IBT - if (is_endbr(*(u32 *)ip)) - ip += 4; -#endif + ip = skip_endbr(ip); memcpy(old_insn, nop_insn, X86_PATCH_SIZE); if (old_addr) { prog = old_insn; -#ifdef CONFIG_X86_KERNEL_IBT - if (is_endbr(*(u32 *)old_addr)) - old_addr += 4; -#endif + old_addr = skip_endbr(old_addr); ret = t == BPF_MOD_CALL ? emit_call(&prog, old_addr, ip) : emit_jump(&prog, old_addr, ip); @@ -372,10 +366,7 @@ static int __bpf_arch_text_poke(void *ip memcpy(new_insn, nop_insn, X86_PATCH_SIZE); if (new_addr) { prog = new_insn; -#ifdef CONFIG_X86_KERNEL_IBT - if (is_endbr(*(u32 *)new_addr)) - new_addr += 4; -#endif + new_addr = skip_endbr(new_addr); ret = t == BPF_MOD_CALL ? emit_call(&prog, new_addr, ip) : emit_jump(&prog, new_addr, ip);
| |