[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <Yhj1oFcTl2RnghBz@hirez.programming.kicks-ass.net>
Date: Fri, 25 Feb 2022 16:28:32 +0100
From: Peter Zijlstra <peterz@...radead.org>
To: Josh Poimboeuf <jpoimboe@...hat.com>
Cc: x86@...nel.org, joao@...rdrivepizza.com, hjl.tools@...il.com,
andrew.cooper3@...rix.com, linux-kernel@...r.kernel.org,
ndesaulniers@...gle.com, keescook@...omium.org,
samitolvanen@...gle.com, mark.rutland@....com,
alyssa.milburn@...el.com, mbenes@...e.cz, rostedt@...dmis.org,
mhiramat@...nel.org, alexei.starovoitov@...il.com
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);
Powered by blists - more mailing lists