lkml.org 
[lkml]   [2022]   [Feb]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: [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);
\
 
 \ /
  Last update: 2022-02-25 16:29    [W:0.595 / U:0.468 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site