* [PATCH v4 00/10] x86/ibt: FineIBT-BHI
@ 2025-02-24 12:37 Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 01/10] x86/cfi: Add warn option Peter Zijlstra
` (9 more replies)
0 siblings, 10 replies; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-24 12:37 UTC (permalink / raw)
To: x86
Cc: linux-kernel, peterz, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, kees, alexei.starovoitov, mhiramat,
jmill
Hi all!
Hopefully final version of these here patches.
As reported, these patches include the cfi=paranoid flag for dealing with the
FineIBT SYSCALL pivot and cfi=bhi for further hardering FineIBT.
Biggest difference since last time is the reworking (vastly simplifying) of
cfi=warn, and getting rid of the ud_type propagation in favour of using
is_cfi_trap().
As reported earlier, available at:
git://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git x86/fineibt-bhi2
Previous version at:
https://lkml.kernel.org/r/20250219162107.880673196@infradead.org
---
Makefile | 3 +
arch/x86/Kconfig | 8 +
arch/x86/include/asm/bug.h | 3 +
arch/x86/include/asm/cfi.h | 10 ++
arch/x86/include/asm/ibt.h | 4 +
arch/x86/kernel/alternative.c | 370 +++++++++++++++++++++++++++++++++++++-----
arch/x86/kernel/cfi.c | 8 +-
arch/x86/kernel/traps.c | 54 +++++-
arch/x86/lib/Makefile | 3 +-
arch/x86/lib/bhi.S | 146 +++++++++++++++++
arch/x86/net/bpf_jit_comp.c | 30 ++--
include/linux/cfi.h | 2 +
kernel/cfi.c | 4 +-
13 files changed, 585 insertions(+), 60 deletions(-)
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v4 01/10] x86/cfi: Add warn option
2025-02-24 12:37 [PATCH v4 00/10] x86/ibt: FineIBT-BHI Peter Zijlstra
@ 2025-02-24 12:37 ` Peter Zijlstra
2025-02-24 18:57 ` Kees Cook
` (2 more replies)
2025-02-24 12:37 ` [PATCH v4 02/10] x86/ibt: Add exact_endbr() helper Peter Zijlstra
` (8 subsequent siblings)
9 siblings, 3 replies; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-24 12:37 UTC (permalink / raw)
To: x86
Cc: linux-kernel, peterz, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, kees, alexei.starovoitov, mhiramat,
jmill
Rebuilding with CFI_PERMISSIVE toggled is such a pain, esp. since
clang is so slow.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
arch/x86/kernel/alternative.c | 3 +++
arch/x86/kernel/cfi.c | 8 ++++----
include/linux/cfi.h | 2 ++
kernel/cfi.c | 4 +++-
4 files changed, 12 insertions(+), 5 deletions(-)
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1022,6 +1022,9 @@ static __init int cfi_parse_cmdline(char
cfi_mode = CFI_FINEIBT;
} else if (!strcmp(str, "norand")) {
cfi_rand = false;
+ } else if (!strcmp(str, "warn")) {
+ pr_alert("CFI mismatch non-fatal!\n");
+ cfi_warn = true;
} else {
pr_err("Ignoring unknown cfi option (%s).", str);
}
--- a/include/linux/cfi.h
+++ b/include/linux/cfi.h
@@ -11,6 +11,8 @@
#include <linux/module.h>
#include <asm/cfi.h>
+extern bool cfi_warn;
+
#ifndef cfi_get_offset
static inline int cfi_get_offset(void)
{
--- a/kernel/cfi.c
+++ b/kernel/cfi.c
@@ -7,6 +7,8 @@
#include <linux/cfi.h>
+bool cfi_warn __ro_after_init = IS_ENABLED(CONFIG_CFI_PERMISSIVE);
+
enum bug_trap_type report_cfi_failure(struct pt_regs *regs, unsigned long addr,
unsigned long *target, u32 type)
{
@@ -17,7 +19,7 @@ enum bug_trap_type report_cfi_failure(st
pr_err("CFI failure at %pS (no target information)\n",
(void *)addr);
- if (IS_ENABLED(CONFIG_CFI_PERMISSIVE)) {
+ if (cfi_warn) {
__warn(NULL, 0, (void *)addr, 0, regs, NULL);
return BUG_TRAP_TYPE_WARN;
}
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v4 02/10] x86/ibt: Add exact_endbr() helper
2025-02-24 12:37 [PATCH v4 00/10] x86/ibt: FineIBT-BHI Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 01/10] x86/cfi: Add warn option Peter Zijlstra
@ 2025-02-24 12:37 ` Peter Zijlstra
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 03/10] x86/traps: Decode 0xEA #UD Peter Zijlstra
` (7 subsequent siblings)
9 siblings, 2 replies; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-24 12:37 UTC (permalink / raw)
To: x86
Cc: linux-kernel, peterz, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, kees, alexei.starovoitov, mhiramat,
jmill
For when we want to exactly match ENDBR, and not everything that we
can scribble it with.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
---
arch/x86/kernel/alternative.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -863,6 +863,17 @@ __noendbr bool is_endbr(u32 *val)
return false;
}
+static __noendbr bool exact_endbr(u32 *val)
+{
+ u32 endbr;
+
+ __get_kernel_nofault(&endbr, val, u32, Efault);
+ return endbr == gen_endbr();
+
+Efault:
+ return false;
+}
+
static void poison_cfi(void *addr);
static void __init_or_module poison_endbr(void *addr)
@@ -1427,10 +1438,9 @@ static void poison_cfi(void *addr)
bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
{
unsigned long addr = regs->ip - fineibt_preamble_ud2;
- u32 endbr, hash;
+ u32 hash;
- __get_kernel_nofault(&endbr, addr, u32, Efault);
- if (endbr != gen_endbr())
+ if (!exact_endbr((void *)addr))
return false;
*target = addr + fineibt_preamble_size;
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v4 03/10] x86/traps: Decode 0xEA #UD
2025-02-24 12:37 [PATCH v4 00/10] x86/ibt: FineIBT-BHI Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 01/10] x86/cfi: Add warn option Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 02/10] x86/ibt: Add exact_endbr() helper Peter Zijlstra
@ 2025-02-24 12:37 ` Peter Zijlstra
2025-02-24 18:58 ` Kees Cook
` (2 more replies)
2025-02-24 12:37 ` [PATCH v4 04/10] x86/traps: Allow custom fixups in handle_bug() Peter Zijlstra
` (6 subsequent siblings)
9 siblings, 3 replies; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-24 12:37 UTC (permalink / raw)
To: x86
Cc: linux-kernel, peterz, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, kees, alexei.starovoitov, mhiramat,
jmill
FineIBT will start using 0xEA as #UD
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
arch/x86/include/asm/bug.h | 1 +
arch/x86/kernel/traps.c | 20 +++++++++++++++++---
2 files changed, 18 insertions(+), 3 deletions(-)
--- a/arch/x86/include/asm/bug.h
+++ b/arch/x86/include/asm/bug.h
@@ -25,6 +25,7 @@
#define BUG_UD2 0xfffe
#define BUG_UD1 0xfffd
#define BUG_UD1_UBSAN 0xfffc
+#define BUG_EA 0xffea
#ifdef CONFIG_GENERIC_BUG
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -96,6 +96,7 @@ __always_inline int is_valid_bugaddr(uns
* Check for UD1 or UD2, accounting for Address Size Override Prefixes.
* If it's a UD1, further decode to determine its use:
*
+ * FineIBT: ea (bad)
* UBSan{0}: 67 0f b9 00 ud1 (%eax),%eax
* UBSan{10}: 67 0f b9 40 10 ud1 0x10(%eax),%eax
* static_call: 0f b9 cc ud1 %esp,%ecx
@@ -113,6 +114,10 @@ __always_inline int decode_bug(unsigned
v = *(u8 *)(addr++);
if (v == INSN_ASOP)
v = *(u8 *)(addr++);
+ if (v == 0xea) {
+ *len = addr - start;
+ return BUG_EA;
+ }
if (v != OPCODE_ESCAPE)
return BUG_NONE;
@@ -309,10 +314,16 @@ static noinstr bool handle_bug(struct pt
switch (ud_type) {
case BUG_UD2:
- if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN ||
- handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) {
- regs->ip += ud_len;
+ if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN) {
+ handled = true;
+ break;
+ }
+ fallthrough;
+
+ case BUG_EA:
+ if (handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) {
handled = true;
+ break;
}
break;
@@ -328,6 +339,9 @@ static noinstr bool handle_bug(struct pt
break;
}
+ if (handled)
+ regs->ip += ud_len;
+
if (regs->flags & X86_EFLAGS_IF)
raw_local_irq_disable();
instrumentation_end();
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v4 04/10] x86/traps: Allow custom fixups in handle_bug()
2025-02-24 12:37 [PATCH v4 00/10] x86/ibt: FineIBT-BHI Peter Zijlstra
` (2 preceding siblings ...)
2025-02-24 12:37 ` [PATCH v4 03/10] x86/traps: Decode 0xEA #UD Peter Zijlstra
@ 2025-02-24 12:37 ` Peter Zijlstra
2025-02-24 18:59 ` Kees Cook
` (2 more replies)
2025-02-24 12:37 ` [PATCH v4 05/10] x86/ibt: Optimize FineIBT sequence Peter Zijlstra
` (5 subsequent siblings)
9 siblings, 3 replies; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-24 12:37 UTC (permalink / raw)
To: x86
Cc: linux-kernel, peterz, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, kees, alexei.starovoitov, mhiramat,
jmill
The normal fixup in handle_bug() is simply continuing at the next
instruction. However upcomming patches make this the wrong thing, so
allow handlers (specifically handle_cfi_failure()) to over-ride
regs->ip.
The callchain is such that the fixup needs to be done before it is
determined if the exception is fatal, as such, revert any changes in
that case.
Additinoally, have handle_cfi_failure() remember the regs->ip value it
starts with for reporting.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
arch/x86/kernel/cfi.c | 8 ++++----
arch/x86/kernel/traps.c | 16 +++++++++++++---
2 files changed, 17 insertions(+), 7 deletions(-)
--- a/arch/x86/kernel/cfi.c
+++ b/arch/x86/kernel/cfi.c
@@ -67,16 +67,16 @@ static bool decode_cfi_insn(struct pt_re
*/
enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
{
- unsigned long target;
+ unsigned long target, addr = regs->ip;
u32 type;
switch (cfi_mode) {
case CFI_KCFI:
- if (!is_cfi_trap(regs->ip))
+ if (!is_cfi_trap(addr))
return BUG_TRAP_TYPE_NONE;
if (!decode_cfi_insn(regs, &target, &type))
- return report_cfi_failure_noaddr(regs, regs->ip);
+ return report_cfi_failure_noaddr(regs, addr);
break;
@@ -90,7 +90,7 @@ enum bug_trap_type handle_cfi_failure(st
return BUG_TRAP_TYPE_NONE;
}
- return report_cfi_failure(regs, regs->ip, &target, type);
+ return report_cfi_failure(regs, addr, &target, type);
}
/*
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -287,11 +287,12 @@ static inline void handle_invalid_op(str
static noinstr bool handle_bug(struct pt_regs *regs)
{
+ unsigned long addr = regs->ip;
bool handled = false;
int ud_type, ud_len;
s32 ud_imm;
- ud_type = decode_bug(regs->ip, &ud_imm, &ud_len);
+ ud_type = decode_bug(addr, &ud_imm, &ud_len);
if (ud_type == BUG_NONE)
return handled;
@@ -339,8 +340,17 @@ static noinstr bool handle_bug(struct pt
break;
}
- if (handled)
- regs->ip += ud_len;
+ /*
+ * When continuing, and regs->ip hasn't changed, move it to the next
+ * instruction. When not continuing execution, restore the instruction
+ * pointer.
+ */
+ if (handled) {
+ if (regs->ip == addr)
+ regs->ip += ud_len;
+ } else {
+ regs->ip = addr;
+ }
if (regs->flags & X86_EFLAGS_IF)
raw_local_irq_disable();
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v4 05/10] x86/ibt: Optimize FineIBT sequence
2025-02-24 12:37 [PATCH v4 00/10] x86/ibt: FineIBT-BHI Peter Zijlstra
` (3 preceding siblings ...)
2025-02-24 12:37 ` [PATCH v4 04/10] x86/traps: Allow custom fixups in handle_bug() Peter Zijlstra
@ 2025-02-24 12:37 ` Peter Zijlstra
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/ibt: Optimize the FineIBT instruction sequence tip-bot2 for Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 06/10] x86/traps: Decode LOCK Jcc.d8 #UD Peter Zijlstra
` (4 subsequent siblings)
9 siblings, 2 replies; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-24 12:37 UTC (permalink / raw)
To: x86
Cc: linux-kernel, peterz, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, kees, alexei.starovoitov, mhiramat,
jmill
Scott notes that non-taken branches are faster. Abuse overlapping code
that traps instead of explicit UD2 instructions.
And LEA does not modify flags and will have less dependencies.
Suggested-by: Scott Constable <scott.d.constable@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
---
arch/x86/kernel/alternative.c | 61 +++++++++++++++++++++++++++---------------
arch/x86/net/bpf_jit_comp.c | 5 +--
2 files changed, 42 insertions(+), 24 deletions(-)
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1053,9 +1053,9 @@ early_param("cfi", cfi_parse_cmdline);
* __cfi_\func: __cfi_\func:
* movl $0x12345678,%eax // 5 endbr64 // 4
* nop subl $0x12345678,%r10d // 7
- * nop jz 1f // 2
- * nop ud2 // 2
- * nop 1: nop // 1
+ * nop jne __cfi_\func+6 // 2
+ * nop nop3 // 3
+ * nop
* nop
* nop
* nop
@@ -1067,37 +1067,50 @@ early_param("cfi", cfi_parse_cmdline);
*
* caller: caller:
* movl $(-0x12345678),%r10d // 6 movl $0x12345678,%r10d // 6
- * addl $-15(%r11),%r10d // 4 sub $16,%r11 // 4
+ * addl $-15(%r11),%r10d // 4 lea -0x10(%r11),%r11 // 4
* je 1f // 2 nop4 // 4
* ud2 // 2
- * 1: call __x86_indirect_thunk_r11 // 5 call *%r11; nop2; // 5
+ * 1: cs call __x86_indirect_thunk_r11 // 6 call *%r11; nop3; // 6
*
*/
-asm( ".pushsection .rodata \n"
- "fineibt_preamble_start: \n"
- " endbr64 \n"
- " subl $0x12345678, %r10d \n"
- " je fineibt_preamble_end \n"
- "fineibt_preamble_ud2: \n"
- " ud2 \n"
- " nop \n"
- "fineibt_preamble_end: \n"
+/*
+ * <fineibt_preamble_start>:
+ * 0: f3 0f 1e fa endbr64
+ * 4: 41 81 <ea> 78 56 34 12 sub $0x12345678, %r10d
+ * b: 75 f9 jne 6 <fineibt_preamble_start+0x6>
+ * d: 0f 1f 00 nopl (%rax)
+ *
+ * Note that the JNE target is the 0xEA byte inside the SUB, this decodes as
+ * (bad) on x86_64 and raises #UD.
+ */
+asm( ".pushsection .rodata \n"
+ "fineibt_preamble_start: \n"
+ " endbr64 \n"
+ " subl $0x12345678, %r10d \n"
+ " jne fineibt_preamble_start+6 \n"
+ ASM_NOP3
+ "fineibt_preamble_end: \n"
".popsection\n"
);
extern u8 fineibt_preamble_start[];
-extern u8 fineibt_preamble_ud2[];
extern u8 fineibt_preamble_end[];
#define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start)
-#define fineibt_preamble_ud2 (fineibt_preamble_ud2 - fineibt_preamble_start)
+#define fineibt_preamble_ud 6
#define fineibt_preamble_hash 7
+/*
+ * <fineibt_caller_start>:
+ * 0: 41 ba 78 56 34 12 mov $0x12345678, %r10d
+ * 6: 4d 8d 5b f0 lea -0x10(%r11), %r11
+ * a: 0f 1f 40 00 nopl 0x0(%rax)
+ */
asm( ".pushsection .rodata \n"
"fineibt_caller_start: \n"
" movl $0x12345678, %r10d \n"
- " sub $16, %r11 \n"
+ " lea -0x10(%r11), %r11 \n"
ASM_NOP4
"fineibt_caller_end: \n"
".popsection \n"
@@ -1428,15 +1441,15 @@ static void poison_cfi(void *addr)
}
/*
- * regs->ip points to a UD2 instruction, return true and fill out target and
- * type when this UD2 is from a FineIBT preamble.
+ * When regs->ip points to a 0xEA byte in the FineIBT preamble,
+ * return true and fill out target and type.
*
* We check the preamble by checking for the ENDBR instruction relative to the
- * UD2 instruction.
+ * 0xEA instruction.
*/
bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
{
- unsigned long addr = regs->ip - fineibt_preamble_ud2;
+ unsigned long addr = regs->ip - fineibt_preamble_ud;
u32 hash;
if (!exact_endbr((void *)addr))
@@ -1447,6 +1460,12 @@ bool decode_fineibt_insn(struct pt_regs
__get_kernel_nofault(&hash, addr + fineibt_preamble_hash, u32, Efault);
*type = (u32)regs->r10 + hash;
+ /*
+ * Since regs->ip points to the middle of an instruction; it cannot
+ * continue with the normal fixup.
+ */
+ regs->ip = *target;
+
return true;
Efault:
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -417,9 +417,8 @@ static void emit_fineibt(u8 **pprog, u32
EMIT_ENDBR();
EMIT3_off32(0x41, 0x81, 0xea, hash); /* subl $hash, %r10d */
- EMIT2(0x74, 0x07); /* jz.d8 +7 */
- EMIT2(0x0f, 0x0b); /* ud2 */
- EMIT1(0x90); /* nop */
+ EMIT2(0x75, 0xf9); /* jne.d8 .-7 */
+ EMIT3(0x0f, 0x1f, 0x00); /* nop3 */
EMIT_ENDBR_POISON();
*pprog = prog;
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v4 06/10] x86/traps: Decode LOCK Jcc.d8 #UD
2025-02-24 12:37 [PATCH v4 00/10] x86/ibt: FineIBT-BHI Peter Zijlstra
` (4 preceding siblings ...)
2025-02-24 12:37 ` [PATCH v4 05/10] x86/ibt: Optimize FineIBT sequence Peter Zijlstra
@ 2025-02-24 12:37 ` Peter Zijlstra
2025-02-24 21:46 ` David Laight
` (2 more replies)
2025-02-24 12:37 ` [PATCH v4 07/10] x86/ibt: Add paranoid FineIBT mode Peter Zijlstra
` (3 subsequent siblings)
9 siblings, 3 replies; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-24 12:37 UTC (permalink / raw)
To: x86
Cc: linux-kernel, peterz, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, kees, alexei.starovoitov, mhiramat,
jmill
Because overlapping code sequences are all the rage.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
---
arch/x86/include/asm/bug.h | 2 ++
arch/x86/kernel/traps.c | 26 +++++++++++++++++++++++---
2 files changed, 25 insertions(+), 3 deletions(-)
--- a/arch/x86/include/asm/bug.h
+++ b/arch/x86/include/asm/bug.h
@@ -17,6 +17,7 @@
* In clang we have UD1s reporting UBSAN failures on X86, 64 and 32bit.
*/
#define INSN_ASOP 0x67
+#define INSN_LOCK 0xf0
#define OPCODE_ESCAPE 0x0f
#define SECOND_BYTE_OPCODE_UD1 0xb9
#define SECOND_BYTE_OPCODE_UD2 0x0b
@@ -26,6 +27,7 @@
#define BUG_UD1 0xfffd
#define BUG_UD1_UBSAN 0xfffc
#define BUG_EA 0xffea
+#define BUG_LOCK 0xfff0
#ifdef CONFIG_GENERIC_BUG
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -97,6 +97,7 @@ __always_inline int is_valid_bugaddr(uns
* If it's a UD1, further decode to determine its use:
*
* FineIBT: ea (bad)
+ * FineIBT: 0f 75 f9 lock jne . - 6
* UBSan{0}: 67 0f b9 00 ud1 (%eax),%eax
* UBSan{10}: 67 0f b9 40 10 ud1 0x10(%eax),%eax
* static_call: 0f b9 cc ud1 %esp,%ecx
@@ -106,6 +107,7 @@ __always_inline int is_valid_bugaddr(uns
__always_inline int decode_bug(unsigned long addr, s32 *imm, int *len)
{
unsigned long start = addr;
+ bool lock = false;
u8 v;
if (addr < TASK_SIZE_MAX)
@@ -114,12 +116,29 @@ __always_inline int decode_bug(unsigned
v = *(u8 *)(addr++);
if (v == INSN_ASOP)
v = *(u8 *)(addr++);
- if (v == 0xea) {
+
+ if (v == INSN_LOCK) {
+ lock = true;
+ v = *(u8 *)(addr++);
+ }
+
+ switch (v) {
+ case 0x70 ... 0x7f: /* Jcc.d8 */
+ addr += 1; /* d8 */
+ *len = addr - start;
+ WARN_ON_ONCE(!lock);
+ return BUG_LOCK;
+
+ case 0xea:
*len = addr - start;
return BUG_EA;
- }
- if (v != OPCODE_ESCAPE)
+
+ case OPCODE_ESCAPE:
+ break;
+
+ default:
return BUG_NONE;
+ }
v = *(u8 *)(addr++);
if (v == SECOND_BYTE_OPCODE_UD2) {
@@ -322,6 +341,7 @@ static noinstr bool handle_bug(struct pt
fallthrough;
case BUG_EA:
+ case BUG_LOCK:
if (handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) {
handled = true;
break;
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v4 07/10] x86/ibt: Add paranoid FineIBT mode
2025-02-24 12:37 [PATCH v4 00/10] x86/ibt: FineIBT-BHI Peter Zijlstra
` (5 preceding siblings ...)
2025-02-24 12:37 ` [PATCH v4 06/10] x86/traps: Decode LOCK Jcc.d8 #UD Peter Zijlstra
@ 2025-02-24 12:37 ` Peter Zijlstra
2025-02-24 19:00 ` Kees Cook
` (2 more replies)
2025-02-24 12:37 ` [PATCH v4 08/10] x86: BHI stubs Peter Zijlstra
` (2 subsequent siblings)
9 siblings, 3 replies; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-24 12:37 UTC (permalink / raw)
To: x86
Cc: linux-kernel, peterz, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, kees, alexei.starovoitov, mhiramat,
jmill
Due to concerns about circumvention attacks against FineIBT on 'naked'
ENDBR, add an additional caller side hash check to FineIBT. This
should make it impossible to pivot over such a 'naked' ENDBR
instruction at the cost of an additional load.
The specific pivot reported was against the SYSCALL entry site and
FRED will have all those holes fixed up.
https://lore.kernel.org/linux-hardening/Z60NwR4w%2F28Z7XUa@ubun/
This specific fineibt_paranoid_start[] sequence was concocted by
Scott.
Reported-by: Jennifer Miller <jmill@asu.edu>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
arch/x86/kernel/alternative.c | 144 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 138 insertions(+), 6 deletions(-)
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -741,6 +741,11 @@ void __init_or_module noinline apply_ret
op2 = insn.opcode.bytes[1];
switch (op1) {
+ case 0x70 ... 0x7f: /* Jcc.d8 */
+ /* See cfi_paranoid. */
+ WARN_ON_ONCE(cfi_mode != CFI_FINEIBT);
+ continue;
+
case CALL_INSN_OPCODE:
case JMP32_INSN_OPCODE:
break;
@@ -994,6 +999,8 @@ u32 cfi_get_func_hash(void *func)
static bool cfi_rand __ro_after_init = true;
static u32 cfi_seed __ro_after_init;
+static bool cfi_paranoid __ro_after_init = false;
+
/*
* Re-hash the CFI hash with a boot-time seed while making sure the result is
* not a valid ENDBR instruction.
@@ -1036,6 +1043,12 @@ static __init int cfi_parse_cmdline(char
} else if (!strcmp(str, "warn")) {
pr_alert("CFI mismatch non-fatal!\n");
cfi_warn = true;
+ } else if (!strcmp(str, "paranoid")) {
+ if (cfi_mode == CFI_FINEIBT) {
+ cfi_paranoid = true;
+ } else {
+ pr_err("Ignoring paranoid; depends on fineibt.\n");
+ }
} else {
pr_err("Ignoring unknown cfi option (%s).", str);
}
@@ -1124,6 +1137,52 @@ extern u8 fineibt_caller_end[];
#define fineibt_caller_jmp (fineibt_caller_size - 2)
+/*
+ * Since FineIBT does hash validation on the callee side it is prone to
+ * circumvention attacks where a 'naked' ENDBR instruction exists that
+ * is not part of the fineibt_preamble sequence.
+ *
+ * Notably the x86 entry points must be ENDBR and equally cannot be
+ * fineibt_preamble.
+ *
+ * The fineibt_paranoid caller sequence adds additional caller side
+ * hash validation. This stops such circumvention attacks dead, but at the cost
+ * of adding a load.
+ *
+ * <fineibt_paranoid_start>:
+ * 0: 41 ba 78 56 34 12 mov $0x12345678, %r10d
+ * 6: 45 3b 53 f7 cmp -0x9(%r11), %r10d
+ * a: 4d 8d 5b <f0> lea -0x10(%r11), %r11
+ * e: 75 fd jne d <fineibt_paranoid_start+0xd>
+ * 10: 41 ff d3 call *%r11
+ * 13: 90 nop
+ *
+ * Notably LEA does not modify flags and can be reordered with the CMP,
+ * avoiding a dependency. Again, using a non-taken (backwards) branch
+ * for the failure case, abusing LEA's immediate 0xf0 as LOCK prefix for the
+ * Jcc.d8, causing #UD.
+ */
+asm( ".pushsection .rodata \n"
+ "fineibt_paranoid_start: \n"
+ " movl $0x12345678, %r10d \n"
+ " cmpl -9(%r11), %r10d \n"
+ " lea -0x10(%r11), %r11 \n"
+ " jne fineibt_paranoid_start+0xd \n"
+ "fineibt_paranoid_ind: \n"
+ " call *%r11 \n"
+ " nop \n"
+ "fineibt_paranoid_end: \n"
+ ".popsection \n"
+);
+
+extern u8 fineibt_paranoid_start[];
+extern u8 fineibt_paranoid_ind[];
+extern u8 fineibt_paranoid_end[];
+
+#define fineibt_paranoid_size (fineibt_paranoid_end - fineibt_paranoid_start)
+#define fineibt_paranoid_ind (fineibt_paranoid_ind - fineibt_paranoid_start)
+#define fineibt_paranoid_ud 0xd
+
static u32 decode_preamble_hash(void *addr)
{
u8 *p = addr;
@@ -1287,18 +1346,48 @@ static int cfi_rewrite_callers(s32 *star
{
s32 *s;
+ BUG_ON(fineibt_paranoid_size != 20);
+
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ struct insn insn;
+ u8 bytes[20];
u32 hash;
+ int ret;
+ u8 op;
addr -= fineibt_caller_size;
hash = decode_caller_hash(addr);
- if (hash) {
+ if (!hash)
+ continue;
+
+ if (!cfi_paranoid) {
text_poke_early(addr, fineibt_caller_start, fineibt_caller_size);
WARN_ON(*(u32 *)(addr + fineibt_caller_hash) != 0x12345678);
text_poke_early(addr + fineibt_caller_hash, &hash, 4);
+ /* rely on apply_retpolines() */
+ continue;
+ }
+
+ /* cfi_paranoid */
+ ret = insn_decode_kernel(&insn, addr + fineibt_caller_size);
+ if (WARN_ON_ONCE(ret < 0))
+ continue;
+
+ op = insn.opcode.bytes[0];
+ if (op != CALL_INSN_OPCODE && op != JMP32_INSN_OPCODE) {
+ WARN_ON_ONCE(1);
+ continue;
}
- /* rely on apply_retpolines() */
+
+ memcpy(bytes, fineibt_paranoid_start, fineibt_paranoid_size);
+ memcpy(bytes + fineibt_caller_hash, &hash, 4);
+
+ ret = emit_indirect(op, 11, bytes + fineibt_paranoid_ind);
+ if (WARN_ON_ONCE(ret != 3))
+ continue;
+
+ text_poke_early(addr, bytes, fineibt_paranoid_size);
}
return 0;
@@ -1315,8 +1404,15 @@ static void __apply_fineibt(s32 *start_r
if (cfi_mode == CFI_AUTO) {
cfi_mode = CFI_KCFI;
- if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT))
+ if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT)) {
+ /*
+ * FRED has much saner context on exception entry and
+ * is less easy to take advantage of.
+ */
+ if (!cpu_feature_enabled(X86_FEATURE_FRED))
+ cfi_paranoid = true;
cfi_mode = CFI_FINEIBT;
+ }
}
/*
@@ -1373,8 +1469,10 @@ static void __apply_fineibt(s32 *start_r
/* now that nobody targets func()+0, remove ENDBR there */
cfi_rewrite_endbr(start_cfi, end_cfi);
- if (builtin)
- pr_info("Using FineIBT CFI\n");
+ if (builtin) {
+ pr_info("Using %sFineIBT CFI\n",
+ cfi_paranoid ? "paranoid " : "");
+ }
return;
default:
@@ -1447,7 +1545,7 @@ static void poison_cfi(void *addr)
* We check the preamble by checking for the ENDBR instruction relative to the
* 0xEA instruction.
*/
-bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
+static bool decode_fineibt_preamble(struct pt_regs *regs, unsigned long *target, u32 *type)
{
unsigned long addr = regs->ip - fineibt_preamble_ud;
u32 hash;
@@ -1472,6 +1570,40 @@ bool decode_fineibt_insn(struct pt_regs
return false;
}
+/*
+ * regs->ip points to a LOCK Jcc.d8 instruction from the fineibt_paranoid_start[]
+ * sequence.
+ */
+static bool decode_fineibt_paranoid(struct pt_regs *regs, unsigned long *target, u32 *type)
+{
+ unsigned long addr = regs->ip - fineibt_paranoid_ud;
+ u32 hash;
+
+ if (!cfi_paranoid || !is_cfi_trap(addr + fineibt_caller_size - LEN_UD2))
+ return false;
+
+ __get_kernel_nofault(&hash, addr + fineibt_caller_hash, u32, Efault);
+ *target = regs->r11 + fineibt_preamble_size;
+ *type = regs->r10;
+
+ /*
+ * Since the trapping instruction is the exact, but LOCK prefixed,
+ * Jcc.d8 that got us here, the normal fixup will work.
+ */
+ return true;
+
+Efault:
+ return false;
+}
+
+bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
+{
+ if (decode_fineibt_paranoid(regs, target, type))
+ return true;
+
+ return decode_fineibt_preamble(regs, target, type);
+}
+
#else
static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v4 08/10] x86: BHI stubs
2025-02-24 12:37 [PATCH v4 00/10] x86/ibt: FineIBT-BHI Peter Zijlstra
` (6 preceding siblings ...)
2025-02-24 12:37 ` [PATCH v4 07/10] x86/ibt: Add paranoid FineIBT mode Peter Zijlstra
@ 2025-02-24 12:37 ` Peter Zijlstra
2025-02-24 19:01 ` Kees Cook
` (3 more replies)
2025-02-24 12:37 ` [PATCH v4 09/10] x86/ibt: Implement FineIBT-BHI mitigation Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 10/10] x86/ibt: Optimize fineibt-bhi arity 1 case Peter Zijlstra
9 siblings, 4 replies; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-24 12:37 UTC (permalink / raw)
To: x86
Cc: linux-kernel, peterz, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, kees, alexei.starovoitov, mhiramat,
jmill
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
arch/x86/include/asm/cfi.h | 4 +
arch/x86/lib/Makefile | 3
arch/x86/lib/bhi.S | 146 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 152 insertions(+), 1 deletion(-)
--- a/arch/x86/include/asm/cfi.h
+++ b/arch/x86/include/asm/cfi.h
@@ -101,6 +101,10 @@ enum cfi_mode {
extern enum cfi_mode cfi_mode;
+typedef u8 bhi_thunk[32];
+extern bhi_thunk __bhi_args[];
+extern bhi_thunk __bhi_args_end[];
+
struct pt_regs;
#ifdef CONFIG_CFI_CLANG
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -66,5 +66,6 @@ endif
lib-y += clear_page_64.o copy_page_64.o
lib-y += memmove_64.o memset_64.o
lib-y += copy_user_64.o copy_user_uncached_64.o
- lib-y += cmpxchg16b_emu.o
+ lib-y += cmpxchg16b_emu.o
+ lib-y += bhi.o
endif
--- /dev/null
+++ b/arch/x86/lib/bhi.S
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/linkage.h>
+#include <asm/unwind_hints.h>
+#include <asm/nospec-branch.h>
+
+/*
+ * Notably, the FineIBT preamble calling these will have ZF set and r10 zero.
+ *
+ * The very last element is in fact larger than 32 bytes, but since its the
+ * last element, this does not matter,
+ *
+ * There are 2 #UD sites, located between 0,1-2,3 and 4,5-6,7 such that they
+ * can be reached using Jcc.d8, these elements (1 and 5) have sufficiently
+ * big alignment holes for this to not stagger the array.
+ */
+
+.pushsection .noinstr.text, "ax"
+
+ .align 32
+SYM_CODE_START(__bhi_args)
+
+#ifdef CONFIG_FINEIBT_BHI
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_0, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_1, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ cmovne %r10, %rdi
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 8
+ ANNOTATE_REACHABLE
+.Lud_1: ud2
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_2, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_3, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_4, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_5, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ cmovne %r10, %r8
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 8
+ ANNOTATE_REACHABLE
+.Lud_2: ud2
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_6, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ cmovne %r10, %r8
+ cmovne %r10, %r9
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_7, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ cmovne %r10, %r8
+ cmovne %r10, %r9
+ cmovne %r10, %rsp
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+#endif /* CONFIG_FINEIBT_BHI */
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_end, SYM_L_GLOBAL)
+ ANNOTATE_NOENDBR
+SYM_CODE_END(__bhi_args)
+
+.popsection
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v4 09/10] x86/ibt: Implement FineIBT-BHI mitigation
2025-02-24 12:37 [PATCH v4 00/10] x86/ibt: FineIBT-BHI Peter Zijlstra
` (7 preceding siblings ...)
2025-02-24 12:37 ` [PATCH v4 08/10] x86: BHI stubs Peter Zijlstra
@ 2025-02-24 12:37 ` Peter Zijlstra
2025-02-25 9:12 ` Peter Zijlstra
` (3 more replies)
2025-02-24 12:37 ` [PATCH v4 10/10] x86/ibt: Optimize fineibt-bhi arity 1 case Peter Zijlstra
9 siblings, 4 replies; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-24 12:37 UTC (permalink / raw)
To: x86
Cc: linux-kernel, peterz, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, kees, alexei.starovoitov, mhiramat,
jmill
While WAIT_FOR_ENDBR is specified to be a full speculation stop; it
has been shown that some implementations are 'leaky' to such an extend
that speculation can escape even the FineIBT preamble.
To deal with this, add additional hardening to the FineIBT preamble.
Notably, using a new LLVM feature:
https://github.com/llvm/llvm-project/commit/e223485c9b38a5579991b8cebb6a200153eee245
which encodes the number of arguments in the kCFI preamble's register.
Using this register<->arity mapping, have the FineIBT preamble CALL
into a stub clobbering the relevant argument registers in the
speculative case.
(This is where Scott goes and gives more details...)
Suggested-by: Scott Constable <scott.d.constable@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
---
Makefile | 3 +
arch/x86/Kconfig | 8 +++
arch/x86/include/asm/cfi.h | 6 ++
arch/x86/kernel/alternative.c | 107 ++++++++++++++++++++++++++++++++++++++----
arch/x86/net/bpf_jit_comp.c | 29 +++++++----
5 files changed, 134 insertions(+), 19 deletions(-)
--- a/Makefile
+++ b/Makefile
@@ -1014,6 +1014,9 @@ CC_FLAGS_CFI := -fsanitize=kcfi
ifdef CONFIG_CFI_ICALL_NORMALIZE_INTEGERS
CC_FLAGS_CFI += -fsanitize-cfi-icall-experimental-normalize-integers
endif
+ifdef CONFIG_FINEIBT_BHI
+ CC_FLAGS_CFI += -fsanitize-kcfi-arity
+endif
ifdef CONFIG_RUST
# Always pass -Zsanitizer-cfi-normalize-integers as CONFIG_RUST selects
# CONFIG_CFI_ICALL_NORMALIZE_INTEGERS.
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2473,6 +2473,10 @@ config CC_HAS_RETURN_THUNK
config CC_HAS_ENTRY_PADDING
def_bool $(cc-option,-fpatchable-function-entry=16,16)
+config CC_HAS_KCFI_ARITY
+ def_bool $(cc-option,-fsanitize=kcfi -fsanitize-kcfi-arity)
+ depends on CC_IS_CLANG && !RUST
+
config FUNCTION_PADDING_CFI
int
default 59 if FUNCTION_ALIGNMENT_64B
@@ -2498,6 +2502,10 @@ config FINEIBT
depends on X86_KERNEL_IBT && CFI_CLANG && MITIGATION_RETPOLINE
select CALL_PADDING
+config FINEIBT_BHI
+ def_bool y
+ depends on FINEIBT && CC_HAS_KCFI_ARITY
+
config HAVE_CALL_THUNKS
def_bool y
depends on CC_HAS_ENTRY_PADDING && MITIGATION_RETHUNK && OBJTOOL
--- a/arch/x86/include/asm/cfi.h
+++ b/arch/x86/include/asm/cfi.h
@@ -100,6 +100,7 @@ enum cfi_mode {
};
extern enum cfi_mode cfi_mode;
+extern bool cfi_bhi;
typedef u8 bhi_thunk[32];
extern bhi_thunk __bhi_args[];
@@ -129,6 +130,7 @@ static inline int cfi_get_offset(void)
#define cfi_get_offset cfi_get_offset
extern u32 cfi_get_func_hash(void *func);
+extern int cfi_get_func_arity(void *func);
#ifdef CONFIG_FINEIBT
extern bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type);
@@ -152,6 +154,10 @@ static inline u32 cfi_get_func_hash(void
{
return 0;
}
+static inline int cfi_get_func_arity(void *func)
+{
+ return 0;
+}
#endif /* CONFIG_CFI_CLANG */
#if HAS_KERNEL_IBT == 1
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -932,6 +932,7 @@ void __init_or_module apply_seal_endbr(s
#endif
enum cfi_mode cfi_mode __ro_after_init = __CFI_DEFAULT;
+bool cfi_bhi __ro_after_init = false;
#ifdef CONFIG_CFI_CLANG
struct bpf_insn;
@@ -992,6 +993,21 @@ u32 cfi_get_func_hash(void *func)
return hash;
}
+
+int cfi_get_func_arity(void *func)
+{
+ bhi_thunk *target;
+ s32 disp;
+
+ if (cfi_mode != CFI_FINEIBT && !cfi_bhi)
+ return 0;
+
+ if (get_kernel_nofault(disp, func - 4))
+ return 0;
+
+ target = func + disp;
+ return target - __bhi_args;
+}
#endif
#ifdef CONFIG_FINEIBT
@@ -1049,6 +1065,12 @@ static __init int cfi_parse_cmdline(char
} else {
pr_err("Ignoring paranoid; depends on fineibt.\n");
}
+ } else if (!strcmp(str, "bhi")) {
+ if (cfi_mode == CFI_FINEIBT) {
+ cfi_bhi = true;
+ } else {
+ pr_err("Ignoring bhi; depends on fineibt.\n");
+ }
} else {
pr_err("Ignoring unknown cfi option (%s).", str);
}
@@ -1101,6 +1123,7 @@ asm( ".pushsection .rodata \n"
"fineibt_preamble_start: \n"
" endbr64 \n"
" subl $0x12345678, %r10d \n"
+ "fineibt_preamble_bhi: \n"
" jne fineibt_preamble_start+6 \n"
ASM_NOP3
"fineibt_preamble_end: \n"
@@ -1108,9 +1131,11 @@ asm( ".pushsection .rodata \n"
);
extern u8 fineibt_preamble_start[];
+extern u8 fineibt_preamble_bhi[];
extern u8 fineibt_preamble_end[];
#define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start)
+#define fineibt_preamble_bhi (fineibt_preamble_bhi - fineibt_preamble_start)
#define fineibt_preamble_ud 6
#define fineibt_preamble_hash 7
@@ -1183,13 +1208,16 @@ extern u8 fineibt_paranoid_end[];
#define fineibt_paranoid_ind (fineibt_paranoid_ind - fineibt_paranoid_start)
#define fineibt_paranoid_ud 0xd
-static u32 decode_preamble_hash(void *addr)
+static u32 decode_preamble_hash(void *addr, int *reg)
{
u8 *p = addr;
- /* b8 78 56 34 12 mov $0x12345678,%eax */
- if (p[0] == 0xb8)
+ /* b8+reg 78 56 34 12 movl $0x12345678,\reg */
+ if (p[0] >= 0xb8 && p[0] < 0xc0) {
+ if (reg)
+ *reg = p[0] - 0xb8;
return *(u32 *)(addr + 1);
+ }
return 0; /* invalid hash value */
}
@@ -1198,11 +1226,11 @@ static u32 decode_caller_hash(void *addr
{
u8 *p = addr;
- /* 41 ba 78 56 34 12 mov $0x12345678,%r10d */
+ /* 41 ba 88 a9 cb ed mov $(-0x12345678),%r10d */
if (p[0] == 0x41 && p[1] == 0xba)
return -*(u32 *)(addr + 2);
- /* e8 0c 78 56 34 12 jmp.d8 +12 */
+ /* e8 0c 88 a9 cb ed jmp.d8 +12 */
if (p[0] == JMP8_INSN_OPCODE && p[1] == fineibt_caller_jmp)
return -*(u32 *)(addr + 2);
@@ -1267,7 +1295,7 @@ static int cfi_rand_preamble(s32 *start,
void *addr = (void *)s + *s;
u32 hash;
- hash = decode_preamble_hash(addr);
+ hash = decode_preamble_hash(addr, NULL);
if (WARN(!hash, "no CFI hash found at: %pS %px %*ph\n",
addr, addr, 5, addr))
return -EINVAL;
@@ -1285,6 +1313,7 @@ static int cfi_rewrite_preamble(s32 *sta
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ int arity;
u32 hash;
/*
@@ -1295,7 +1324,7 @@ static int cfi_rewrite_preamble(s32 *sta
if (!is_endbr(addr + 16))
continue;
- hash = decode_preamble_hash(addr);
+ hash = decode_preamble_hash(addr, &arity);
if (WARN(!hash, "no CFI hash found at: %pS %px %*ph\n",
addr, addr, 5, addr))
return -EINVAL;
@@ -1303,6 +1332,19 @@ static int cfi_rewrite_preamble(s32 *sta
text_poke_early(addr, fineibt_preamble_start, fineibt_preamble_size);
WARN_ON(*(u32 *)(addr + fineibt_preamble_hash) != 0x12345678);
text_poke_early(addr + fineibt_preamble_hash, &hash, 4);
+
+ WARN_ONCE(!IS_ENABLED(CONFIG_FINEIBT_BHI) && arity,
+ "kCFI preamble has wrong register at: %pS %*ph\n",
+ addr, 5, addr);
+
+ if (!cfi_bhi || !arity)
+ continue;
+
+ text_poke_early(addr + fineibt_preamble_bhi,
+ text_gen_insn(CALL_INSN_OPCODE,
+ addr + fineibt_preamble_bhi,
+ __bhi_args[arity]),
+ CALL_INSN_SIZE);
}
return 0;
@@ -1470,8 +1512,9 @@ static void __apply_fineibt(s32 *start_r
cfi_rewrite_endbr(start_cfi, end_cfi);
if (builtin) {
- pr_info("Using %sFineIBT CFI\n",
- cfi_paranoid ? "paranoid " : "");
+ pr_info("Using %sFineIBT%s CFI\n",
+ cfi_paranoid ? "paranoid " : "",
+ cfi_bhi ? "+BHI" : "");
}
return;
@@ -1522,7 +1565,7 @@ static void poison_cfi(void *addr)
/*
* kCFI prefix should start with a valid hash.
*/
- if (!decode_preamble_hash(addr))
+ if (!decode_preamble_hash(addr, NULL))
break;
/*
@@ -1571,6 +1614,47 @@ static bool decode_fineibt_preamble(stru
}
/*
+ * regs->ip points to one of the UD2 in __bhi_args[].
+ */
+static bool decode_fineibt_bhi(struct pt_regs *regs, unsigned long *target, u32 *type)
+{
+ unsigned long addr;
+ u32 hash;
+
+ if (!cfi_bhi)
+ return false;
+
+ if (regs->ip < (unsigned long)__bhi_args ||
+ regs->ip >= (unsigned long)__bhi_args_end)
+ return false;
+
+ /*
+ * Fetch the return address from the stack, this points to the
+ * FineIBT preamble. Since the CALL instruction is in the 5 last
+ * bytes of the preamble, the return address is in fact the target
+ * address.
+ */
+ __get_kernel_nofault(&addr, regs->sp, unsigned long, Efault);
+ *target = addr;
+
+ addr -= fineibt_preamble_size;
+ if (!exact_endbr((void *)addr))
+ return false;
+
+ __get_kernel_nofault(&hash, addr + fineibt_preamble_hash, u32, Efault);
+ *type = (u32)regs->r10 + hash;
+
+ /*
+ * The UD2 sites are constructed with a RET immediately following,
+ * as such the non-fatal case can use the regular fixup.
+ */
+ return true;
+
+Efault:
+ return false;
+}
+
+/*
* regs->ip points to a LOCK Jcc.d8 instruction from the fineibt_paranoid_start[]
* sequence.
*/
@@ -1601,6 +1685,9 @@ bool decode_fineibt_insn(struct pt_regs
if (decode_fineibt_paranoid(regs, target, type))
return true;
+ if (decode_fineibt_bhi(regs, target, type))
+ return true;
+
return decode_fineibt_preamble(regs, target, type);
}
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -410,15 +410,20 @@ static void emit_nops(u8 **pprog, int le
* Emit the various CFI preambles, see asm/cfi.h and the comments about FineIBT
* in arch/x86/kernel/alternative.c
*/
+static int emit_call(u8 **prog, void *func, void *ip);
-static void emit_fineibt(u8 **pprog, u32 hash)
+static void emit_fineibt(u8 **pprog, u8 *ip, u32 hash, int arity)
{
u8 *prog = *pprog;
EMIT_ENDBR();
EMIT3_off32(0x41, 0x81, 0xea, hash); /* subl $hash, %r10d */
- EMIT2(0x75, 0xf9); /* jne.d8 .-7 */
- EMIT3(0x0f, 0x1f, 0x00); /* nop3 */
+ if (cfi_bhi) {
+ emit_call(&prog, __bhi_args[arity], ip + 11);
+ } else {
+ EMIT2(0x75, 0xf9); /* jne.d8 .-7 */
+ EMIT3(0x0f, 0x1f, 0x00); /* nop3 */
+ }
EMIT_ENDBR_POISON();
*pprog = prog;
@@ -447,13 +452,13 @@ static void emit_kcfi(u8 **pprog, u32 ha
*pprog = prog;
}
-static void emit_cfi(u8 **pprog, u32 hash)
+static void emit_cfi(u8 **pprog, u8 *ip, u32 hash, int arity)
{
u8 *prog = *pprog;
switch (cfi_mode) {
case CFI_FINEIBT:
- emit_fineibt(&prog, hash);
+ emit_fineibt(&prog, ip, hash, arity);
break;
case CFI_KCFI:
@@ -504,13 +509,17 @@ static void emit_prologue_tail_call(u8 *
* bpf_tail_call helper will skip the first X86_TAIL_CALL_OFFSET bytes
* while jumping to another program
*/
-static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf,
+static void emit_prologue(u8 **pprog, u8 *ip, u32 stack_depth, bool ebpf_from_cbpf,
bool tail_call_reachable, bool is_subprog,
bool is_exception_cb)
{
u8 *prog = *pprog;
- emit_cfi(&prog, is_subprog ? cfi_bpf_subprog_hash : cfi_bpf_hash);
+ if (is_subprog) {
+ emit_cfi(&prog, ip, cfi_bpf_subprog_hash, 5);
+ } else {
+ emit_cfi(&prog, ip, cfi_bpf_hash, 1);
+ }
/* BPF trampoline can be made to work without these nops,
* but let's waste 5 bytes for now and optimize later
*/
@@ -1479,7 +1488,7 @@ static int do_jit(struct bpf_prog *bpf_p
detect_reg_usage(insn, insn_cnt, callee_regs_used);
- emit_prologue(&prog, stack_depth,
+ emit_prologue(&prog, image, stack_depth,
bpf_prog_was_classic(bpf_prog), tail_call_reachable,
bpf_is_subprog(bpf_prog), bpf_prog->aux->exception_cb);
/* Exception callback will clobber callee regs for its own use, and
@@ -3046,7 +3055,9 @@ static int __arch_prepare_bpf_trampoline
/*
* Indirect call for bpf_struct_ops
*/
- emit_cfi(&prog, cfi_get_func_hash(func_addr));
+ emit_cfi(&prog, image,
+ cfi_get_func_hash(func_addr),
+ cfi_get_func_arity(func_addr));
} else {
/*
* Direct-call fentry stub, as such it needs accounting for the
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v4 10/10] x86/ibt: Optimize fineibt-bhi arity 1 case
2025-02-24 12:37 [PATCH v4 00/10] x86/ibt: FineIBT-BHI Peter Zijlstra
` (8 preceding siblings ...)
2025-02-24 12:37 ` [PATCH v4 09/10] x86/ibt: Implement FineIBT-BHI mitigation Peter Zijlstra
@ 2025-02-24 12:37 ` Peter Zijlstra
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
` (2 more replies)
9 siblings, 3 replies; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-24 12:37 UTC (permalink / raw)
To: x86
Cc: linux-kernel, peterz, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, kees, alexei.starovoitov, mhiramat,
jmill
Saves a CALL to an out-of-line thunk for the common case of 1
argument.
Suggested-by: Scott Constable <scott.d.constable@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
---
arch/x86/include/asm/ibt.h | 4 ++
arch/x86/kernel/alternative.c | 59 +++++++++++++++++++++++++++++++++++-------
2 files changed, 54 insertions(+), 9 deletions(-)
--- a/arch/x86/include/asm/ibt.h
+++ b/arch/x86/include/asm/ibt.h
@@ -70,6 +70,10 @@ static inline bool __is_endbr(u32 val)
if (val == gen_endbr_poison())
return true;
+ /* See cfi_fineibt_bhi_preamble() */
+ if (IS_ENABLED(CONFIG_FINEIBT_BHI) && val == 0x001f0ff5)
+ return true;
+
val &= ~0x01000000U; /* ENDBR32 -> ENDBR64 */
return val == gen_endbr();
}
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1307,6 +1307,53 @@ static int cfi_rand_preamble(s32 *start,
return 0;
}
+static void cfi_fineibt_bhi_preamble(void *addr, int arity)
+{
+ if (!arity)
+ return;
+
+ if (!cfi_warn && arity == 1) {
+ /*
+ * Crazy scheme to allow arity-1 inline:
+ *
+ * __cfi_foo:
+ * 0: f3 0f 1e fa endbr64
+ * 4: 41 81 <ea> 78 56 34 12 sub 0x12345678, %r10d
+ * b: 49 0f 45 fa cmovne %r10, %rdi
+ * f: 75 f5 jne __cfi_foo+6
+ * 11: 0f 1f 00 nopl (%rax)
+ *
+ * Code that direct calls to foo()+0, decodes the tail end as:
+ *
+ * foo:
+ * 0: f5 cmc
+ * 1: 0f 1f 00 nopl (%rax)
+ *
+ * which clobbers CF, but does not affect anything ABI
+ * wise.
+ *
+ * Notably, this scheme is incompatible with permissive CFI
+ * because the CMOVcc is unconditional and RDI will have been
+ * clobbered.
+ */
+ const u8 magic[9] = {
+ 0x49, 0x0f, 0x45, 0xfa,
+ 0x75, 0xf5,
+ BYTES_NOP3,
+ };
+
+ text_poke_early(addr + fineibt_preamble_bhi, magic, 9);
+
+ return;
+ }
+
+ text_poke_early(addr + fineibt_preamble_bhi,
+ text_gen_insn(CALL_INSN_OPCODE,
+ addr + fineibt_preamble_bhi,
+ __bhi_args[arity]),
+ CALL_INSN_SIZE);
+}
+
static int cfi_rewrite_preamble(s32 *start, s32 *end)
{
s32 *s;
@@ -1337,14 +1384,8 @@ static int cfi_rewrite_preamble(s32 *sta
"kCFI preamble has wrong register at: %pS %*ph\n",
addr, 5, addr);
- if (!cfi_bhi || !arity)
- continue;
-
- text_poke_early(addr + fineibt_preamble_bhi,
- text_gen_insn(CALL_INSN_OPCODE,
- addr + fineibt_preamble_bhi,
- __bhi_args[arity]),
- CALL_INSN_SIZE);
+ if (cfi_bhi)
+ cfi_fineibt_bhi_preamble(addr, arity);
}
return 0;
@@ -1357,7 +1398,7 @@ static void cfi_rewrite_endbr(s32 *start
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
- if (!is_endbr(addr + 16))
+ if (!exact_endbr(addr + 16))
continue;
poison_endbr(addr + 16);
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v4 01/10] x86/cfi: Add warn option
2025-02-24 12:37 ` [PATCH v4 01/10] x86/cfi: Add warn option Peter Zijlstra
@ 2025-02-24 18:57 ` Kees Cook
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/cfi: Add 'cfi=warn' boot option tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: Kees Cook @ 2025-02-24 18:57 UTC (permalink / raw)
To: Peter Zijlstra
Cc: x86, linux-kernel, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, alexei.starovoitov, mhiramat, jmill
On Mon, Feb 24, 2025 at 01:37:04PM +0100, Peter Zijlstra wrote:
> Rebuilding with CFI_PERMISSIVE toggled is such a pain, esp. since
> clang is so slow.
>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Lovely :)
Reviewed-by: Kees Cook <kees@kernel.org>
--
Kees Cook
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v4 03/10] x86/traps: Decode 0xEA #UD
2025-02-24 12:37 ` [PATCH v4 03/10] x86/traps: Decode 0xEA #UD Peter Zijlstra
@ 2025-02-24 18:58 ` Kees Cook
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/traps: Decode 0xEA instructions as #UD tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: Kees Cook @ 2025-02-24 18:58 UTC (permalink / raw)
To: Peter Zijlstra
Cc: x86, linux-kernel, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, alexei.starovoitov, mhiramat, jmill
On Mon, Feb 24, 2025 at 01:37:06PM +0100, Peter Zijlstra wrote:
> FineIBT will start using 0xEA as #UD
>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Yup, looks good.
Reviewed-by: Kees Cook <kees@kernel.org>
--
Kees Cook
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v4 04/10] x86/traps: Allow custom fixups in handle_bug()
2025-02-24 12:37 ` [PATCH v4 04/10] x86/traps: Allow custom fixups in handle_bug() Peter Zijlstra
@ 2025-02-24 18:59 ` Kees Cook
2025-02-25 8:54 ` Peter Zijlstra
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2 siblings, 1 reply; 56+ messages in thread
From: Kees Cook @ 2025-02-24 18:59 UTC (permalink / raw)
To: Peter Zijlstra
Cc: x86, linux-kernel, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, alexei.starovoitov, mhiramat, jmill
On Mon, Feb 24, 2025 at 01:37:07PM +0100, Peter Zijlstra wrote:
> The normal fixup in handle_bug() is simply continuing at the next
> instruction. However upcomming patches make this the wrong thing, so
> allow handlers (specifically handle_cfi_failure()) to over-ride
> regs->ip.
>
> The callchain is such that the fixup needs to be done before it is
> determined if the exception is fatal, as such, revert any changes in
> that case.
>
> Additinoally, have handle_cfi_failure() remember the regs->ip value it
typo above, if you want to tweak that in your tree.
> starts with for reporting.
>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Thanks for the added comment, my future brain will appreciate it. :)
Reviewed-by: Kees Cook <kees@kernel.org>
--
Kees Cook
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v4 07/10] x86/ibt: Add paranoid FineIBT mode
2025-02-24 12:37 ` [PATCH v4 07/10] x86/ibt: Add paranoid FineIBT mode Peter Zijlstra
@ 2025-02-24 19:00 ` Kees Cook
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: Kees Cook @ 2025-02-24 19:00 UTC (permalink / raw)
To: Peter Zijlstra
Cc: x86, linux-kernel, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, alexei.starovoitov, mhiramat, jmill
On Mon, Feb 24, 2025 at 01:37:10PM +0100, Peter Zijlstra wrote:
> Due to concerns about circumvention attacks against FineIBT on 'naked'
> ENDBR, add an additional caller side hash check to FineIBT. This
> should make it impossible to pivot over such a 'naked' ENDBR
> instruction at the cost of an additional load.
>
> The specific pivot reported was against the SYSCALL entry site and
> FRED will have all those holes fixed up.
>
> https://lore.kernel.org/linux-hardening/Z60NwR4w%2F28Z7XUa@ubun/
>
> This specific fineibt_paranoid_start[] sequence was concocted by
> Scott.
>
> Reported-by: Jennifer Miller <jmill@asu.edu>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Great! I'm happy to see the pre-call checking. :)
Reviewed-by: Kees Cook <kees@kernel.org>
--
Kees Cook
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v4 08/10] x86: BHI stubs
2025-02-24 12:37 ` [PATCH v4 08/10] x86: BHI stubs Peter Zijlstra
@ 2025-02-24 19:01 ` Kees Cook
2025-02-25 8:52 ` Peter Zijlstra
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
` (2 subsequent siblings)
3 siblings, 1 reply; 56+ messages in thread
From: Kees Cook @ 2025-02-24 19:01 UTC (permalink / raw)
To: Peter Zijlstra
Cc: x86, linux-kernel, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, alexei.starovoitov, mhiramat, jmill
On Mon, Feb 24, 2025 at 01:37:11PM +0100, Peter Zijlstra wrote:
>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Did this commit log go missing?
--
Kees Cook
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v4 06/10] x86/traps: Decode LOCK Jcc.d8 #UD
2025-02-24 12:37 ` [PATCH v4 06/10] x86/traps: Decode LOCK Jcc.d8 #UD Peter Zijlstra
@ 2025-02-24 21:46 ` David Laight
2025-02-25 18:33 ` Kees Cook
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/traps: Decode LOCK Jcc.d8 as #UD tip-bot2 for Peter Zijlstra
2 siblings, 1 reply; 56+ messages in thread
From: David Laight @ 2025-02-24 21:46 UTC (permalink / raw)
To: Peter Zijlstra
Cc: x86, linux-kernel, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, kees, alexei.starovoitov, mhiramat,
jmill
On Mon, 24 Feb 2025 13:37:09 +0100
Peter Zijlstra <peterz@infradead.org> wrote:
> Because overlapping code sequences are all the rage.
>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> Reviewed-by: Kees Cook <kees@kernel.org>
> ---
> arch/x86/include/asm/bug.h | 2 ++
> arch/x86/kernel/traps.c | 26 +++++++++++++++++++++++---
> 2 files changed, 25 insertions(+), 3 deletions(-)
>
> --- a/arch/x86/include/asm/bug.h
> +++ b/arch/x86/include/asm/bug.h
> @@ -17,6 +17,7 @@
> * In clang we have UD1s reporting UBSAN failures on X86, 64 and 32bit.
> */
> #define INSN_ASOP 0x67
> +#define INSN_LOCK 0xf0
> #define OPCODE_ESCAPE 0x0f
> #define SECOND_BYTE_OPCODE_UD1 0xb9
> #define SECOND_BYTE_OPCODE_UD2 0x0b
> @@ -26,6 +27,7 @@
> #define BUG_UD1 0xfffd
> #define BUG_UD1_UBSAN 0xfffc
> #define BUG_EA 0xffea
> +#define BUG_LOCK 0xfff0
>
> #ifdef CONFIG_GENERIC_BUG
>
> --- a/arch/x86/kernel/traps.c
> +++ b/arch/x86/kernel/traps.c
> @@ -97,6 +97,7 @@ __always_inline int is_valid_bugaddr(uns
> * If it's a UD1, further decode to determine its use:
> *
> * FineIBT: ea (bad)
> + * FineIBT: 0f 75 f9 lock jne . - 6
^^ nibble swapped
David
> * UBSan{0}: 67 0f b9 00 ud1 (%eax),%eax
> * UBSan{10}: 67 0f b9 40 10 ud1 0x10(%eax),%eax
> * static_call: 0f b9 cc ud1 %esp,%ecx
> @@ -106,6 +107,7 @@ __always_inline int is_valid_bugaddr(uns
> __always_inline int decode_bug(unsigned long addr, s32 *imm, int *len)
> {
> unsigned long start = addr;
> + bool lock = false;
> u8 v;
>
> if (addr < TASK_SIZE_MAX)
> @@ -114,12 +116,29 @@ __always_inline int decode_bug(unsigned
> v = *(u8 *)(addr++);
> if (v == INSN_ASOP)
> v = *(u8 *)(addr++);
> - if (v == 0xea) {
> +
> + if (v == INSN_LOCK) {
> + lock = true;
> + v = *(u8 *)(addr++);
> + }
> +
> + switch (v) {
> + case 0x70 ... 0x7f: /* Jcc.d8 */
> + addr += 1; /* d8 */
> + *len = addr - start;
> + WARN_ON_ONCE(!lock);
> + return BUG_LOCK;
> +
> + case 0xea:
> *len = addr - start;
> return BUG_EA;
> - }
> - if (v != OPCODE_ESCAPE)
> +
> + case OPCODE_ESCAPE:
> + break;
> +
> + default:
> return BUG_NONE;
> + }
>
> v = *(u8 *)(addr++);
> if (v == SECOND_BYTE_OPCODE_UD2) {
> @@ -322,6 +341,7 @@ static noinstr bool handle_bug(struct pt
> fallthrough;
>
> case BUG_EA:
> + case BUG_LOCK:
> if (handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) {
> handled = true;
> break;
>
>
>
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v4 08/10] x86: BHI stubs
2025-02-24 19:01 ` Kees Cook
@ 2025-02-25 8:52 ` Peter Zijlstra
2025-02-25 18:31 ` Kees Cook
0 siblings, 1 reply; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-25 8:52 UTC (permalink / raw)
To: Kees Cook
Cc: x86, linux-kernel, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, alexei.starovoitov, mhiramat, jmill
On Mon, Feb 24, 2025 at 11:01:02AM -0800, Kees Cook wrote:
> On Mon, Feb 24, 2025 at 01:37:11PM +0100, Peter Zijlstra wrote:
> >
> > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
>
> Did this commit log go missing?
Nah, it never had one.
How does this sound?
---
Add an array of code thunks, to be called from the FineIBT preamble,
clobbering the first 'n' argument registers for speculative execution.
Notably the 0th entry will clobber no argument registers and will never
be used, it exists so the array can be naturally indexed, while the 7th
entry will clobber all the 6 argument registers and also RSP in order to
mess up stack based arguments.
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v4 04/10] x86/traps: Allow custom fixups in handle_bug()
2025-02-24 18:59 ` Kees Cook
@ 2025-02-25 8:54 ` Peter Zijlstra
0 siblings, 0 replies; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-25 8:54 UTC (permalink / raw)
To: Kees Cook
Cc: x86, linux-kernel, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, alexei.starovoitov, mhiramat, jmill
On Mon, Feb 24, 2025 at 10:59:21AM -0800, Kees Cook wrote:
> On Mon, Feb 24, 2025 at 01:37:07PM +0100, Peter Zijlstra wrote:
> > The normal fixup in handle_bug() is simply continuing at the next
> > instruction. However upcomming patches make this the wrong thing, so
> > allow handlers (specifically handle_cfi_failure()) to over-ride
> > regs->ip.
> >
> > The callchain is such that the fixup needs to be done before it is
> > determined if the exception is fatal, as such, revert any changes in
> > that case.
> >
> > Additinoally, have handle_cfi_failure() remember the regs->ip value it
>
> typo above, if you want to tweak that in your tree.
Typing is forever hard :-)
> > starts with for reporting.
> >
> > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
>
> Thanks for the added comment, my future brain will appreciate it. :)
>
> Reviewed-by: Kees Cook <kees@kernel.org>
Thanks!
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v4 09/10] x86/ibt: Implement FineIBT-BHI mitigation
2025-02-24 12:37 ` [PATCH v4 09/10] x86/ibt: Implement FineIBT-BHI mitigation Peter Zijlstra
@ 2025-02-25 9:12 ` Peter Zijlstra
2025-02-26 0:04 ` Constable, Scott D
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
` (2 subsequent siblings)
3 siblings, 1 reply; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-25 9:12 UTC (permalink / raw)
To: x86
Cc: linux-kernel, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, kees, alexei.starovoitov, mhiramat,
jmill
On Mon, Feb 24, 2025 at 01:37:12PM +0100, Peter Zijlstra wrote:
> While WAIT_FOR_ENDBR is specified to be a full speculation stop; it
> has been shown that some implementations are 'leaky' to such an extend
> that speculation can escape even the FineIBT preamble.
>
> To deal with this, add additional hardening to the FineIBT preamble.
>
> Notably, using a new LLVM feature:
>
> https://github.com/llvm/llvm-project/commit/e223485c9b38a5579991b8cebb6a200153eee245
>
> which encodes the number of arguments in the kCFI preamble's register.
>
> Using this register<->arity mapping, have the FineIBT preamble CALL
> into a stub clobbering the relevant argument registers in the
> speculative case.
>
> (This is where Scott goes and gives more details...)
Scott, could you give a blurb here? Would the below cover things?
The basic setup, for 1 argument, is something like:
__bhi_args_1:
jne .Lud
cmovne %r10, %rdi
ret
int3
__cfi_foo:
endbr
subl $hash, %r10d
call __bhi_args_1
foo:
osp nop3
...
such that when speculation of an indirect call is maliciously steered
here from a non-matching site, the hash check (__cfi_foo's SUB) will not
match, resulting in !ZF and non-zero R10. Subsequently the __bhi_args
stub will either hit #UD exception, which kills speculation, or when
steered wrong, hit the cmovne, which will then clobber the argument
register RDI with whatever non-zero garbage sits in R10. Making it much
harder to control whatever foo normally does with its input argument.
Additionally, CFI hashes are randomized at boot, making it much harder
still to predict/control the non-zero value.
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v4 08/10] x86: BHI stubs
2025-02-25 8:52 ` Peter Zijlstra
@ 2025-02-25 18:31 ` Kees Cook
0 siblings, 0 replies; 56+ messages in thread
From: Kees Cook @ 2025-02-25 18:31 UTC (permalink / raw)
To: Peter Zijlstra
Cc: x86, linux-kernel, alyssa.milburn, scott.d.constable, joao,
andrew.cooper3, jpoimboe, jose.marchesi, hjl.tools, ndesaulniers,
samitolvanen, nathan, ojeda, alexei.starovoitov, mhiramat, jmill
On Tue, Feb 25, 2025 at 09:52:12AM +0100, Peter Zijlstra wrote:
> On Mon, Feb 24, 2025 at 11:01:02AM -0800, Kees Cook wrote:
>
> > On Mon, Feb 24, 2025 at 01:37:11PM +0100, Peter Zijlstra wrote:
> > >
> > > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> >
> > Did this commit log go missing?
>
> Nah, it never had one.
>
> How does this sound?
>
> ---
>
> Add an array of code thunks, to be called from the FineIBT preamble,
> clobbering the first 'n' argument registers for speculative execution.
>
> Notably the 0th entry will clobber no argument registers and will never
> be used, it exists so the array can be naturally indexed, while the 7th
> entry will clobber all the 6 argument registers and also RSP in order to
> mess up stack based arguments.
>
Yes, this reads well. Thanks!
Reviewed-by: Kees Cook <kees@kernel.org>
--
Kees Cook
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v4 06/10] x86/traps: Decode LOCK Jcc.d8 #UD
2025-02-24 21:46 ` David Laight
@ 2025-02-25 18:33 ` Kees Cook
0 siblings, 0 replies; 56+ messages in thread
From: Kees Cook @ 2025-02-25 18:33 UTC (permalink / raw)
To: David Laight
Cc: Peter Zijlstra, x86, linux-kernel, alyssa.milburn,
scott.d.constable, joao, andrew.cooper3, jpoimboe, jose.marchesi,
hjl.tools, ndesaulniers, samitolvanen, nathan, ojeda,
alexei.starovoitov, mhiramat, jmill
On Mon, Feb 24, 2025 at 09:46:12PM +0000, David Laight wrote:
> On Mon, 24 Feb 2025 13:37:09 +0100
> Peter Zijlstra <peterz@infradead.org> wrote:
>
> > Because overlapping code sequences are all the rage.
> >
> > Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> > Reviewed-by: Kees Cook <kees@kernel.org>
> > ---
> > arch/x86/include/asm/bug.h | 2 ++
> > arch/x86/kernel/traps.c | 26 +++++++++++++++++++++++---
> > 2 files changed, 25 insertions(+), 3 deletions(-)
> >
> > --- a/arch/x86/include/asm/bug.h
> > +++ b/arch/x86/include/asm/bug.h
> > @@ -17,6 +17,7 @@
> > * In clang we have UD1s reporting UBSAN failures on X86, 64 and 32bit.
> > */
> > #define INSN_ASOP 0x67
> > +#define INSN_LOCK 0xf0
> > #define OPCODE_ESCAPE 0x0f
> > #define SECOND_BYTE_OPCODE_UD1 0xb9
> > #define SECOND_BYTE_OPCODE_UD2 0x0b
> > @@ -26,6 +27,7 @@
> > #define BUG_UD1 0xfffd
> > #define BUG_UD1_UBSAN 0xfffc
> > #define BUG_EA 0xffea
> > +#define BUG_LOCK 0xfff0
> >
> > #ifdef CONFIG_GENERIC_BUG
> >
> > --- a/arch/x86/kernel/traps.c
> > +++ b/arch/x86/kernel/traps.c
> > @@ -97,6 +97,7 @@ __always_inline int is_valid_bugaddr(uns
> > * If it's a UD1, further decode to determine its use:
> > *
> > * FineIBT: ea (bad)
> > + * FineIBT: 0f 75 f9 lock jne . - 6
> ^^ nibble swapped
Oh, good catch!
--
Kees Cook
^ permalink raw reply [flat|nested] 56+ messages in thread
* RE: [PATCH v4 09/10] x86/ibt: Implement FineIBT-BHI mitigation
2025-02-25 9:12 ` Peter Zijlstra
@ 2025-02-26 0:04 ` Constable, Scott D
0 siblings, 0 replies; 56+ messages in thread
From: Constable, Scott D @ 2025-02-26 0:04 UTC (permalink / raw)
To: Peter Zijlstra, x86@kernel.org
Cc: linux-kernel@vger.kernel.org, Milburn, Alyssa,
joao@overdrivepizza.com, andrew.cooper3@citrix.com,
jpoimboe@kernel.org, jose.marchesi@oracle.com,
hjl.tools@gmail.com, ndesaulniers@google.com,
samitolvanen@google.com, nathan@kernel.org, ojeda@kernel.org,
kees@kernel.org, alexei.starovoitov@gmail.com,
mhiramat@kernel.org, jmill@asu.edu
Peter's example is perfectly valid. I can elaborate on the broader goals:
Microarchitectural attacks such as Branch History Injection (BHI) and Intra-mode Branch Target Injection (IMBTI) [1] can cause an indirect call to mispredict to an adversary-influenced target within the same hardware domain (e.g., within the kernel). Instructions at the mispredicted target may execute speculatively and potentially expose kernel data (e.g., to a user-mode adversary) through a microarchitectural covert channel such as CPU cache state.
CET-IBT [2] is a coarse-grained control-flow integrity (CFI) ISA extension that enforces that each indirect call (or indirect jump) must land on an ENDBR (end branch) instruction, even speculatively*. FineIBT is a software technique that refines CET-IBT by associating each function type with a 32-bit hash and enforcing (at the callee) that the hash of the caller's function pointer type matches the hash of the callee's function type. However, recent research [3] has demonstrated that the conditional branch that enforces FineIBT's hash check can be coerced to mispredict, potentially allowing an adversary to speculatively bypass the hash check:
fineibt_target:
ENDBR64
SUB R10d, 0x01234567
JZ .fineibt_target_body # Even if the hash check fails and ZF=0, this branch could still mispredict as taken
UD2
.fineibt_target_body:
...
The techniques demonstrated in [3] require the attacker to be able to control the contents of at least one live register at the mispredicted target. Therefore, this patch set introduces a sequence of CMOV instructions at each indirect-callable target that poisons every live register with data that the attacker cannot control whenever the FineIBT hash check fails, thus mitigating any potential attack.
The security provided by this scheme has been discussed in detail on an earlier thread [4].
[1] https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/branch-history-injection.html
[2] Intel Software Developer's Manual, Volume 1, Chapter 18
[3] https://www.vusec.net/projects/native-bhi/
[4] https://lore.kernel.org/lkml/20240927194925.707462984@infradead.org/
*There are some caveats for certain processors, see [1] for more info
Regards,
Scott Constable
-----Original Message-----
From: Peter Zijlstra <peterz@infradead.org>
Sent: Tuesday, February 25, 2025 1:12 AM
To: x86@kernel.org
Cc: linux-kernel@vger.kernel.org; Milburn, Alyssa <alyssa.milburn@intel.com>; Constable, Scott D <scott.d.constable@intel.com>; joao@overdrivepizza.com; andrew.cooper3@citrix.com; jpoimboe@kernel.org; jose.marchesi@oracle.com; hjl.tools@gmail.com; ndesaulniers@google.com; samitolvanen@google.com; nathan@kernel.org; ojeda@kernel.org; kees@kernel.org; alexei.starovoitov@gmail.com; mhiramat@kernel.org; jmill@asu.edu
Subject: Re: [PATCH v4 09/10] x86/ibt: Implement FineIBT-BHI mitigation
On Mon, Feb 24, 2025 at 01:37:12PM +0100, Peter Zijlstra wrote:
> While WAIT_FOR_ENDBR is specified to be a full speculation stop; it
> has been shown that some implementations are 'leaky' to such an extend
> that speculation can escape even the FineIBT preamble.
>
> To deal with this, add additional hardening to the FineIBT preamble.
>
> Notably, using a new LLVM feature:
>
>
> https://github.com/llvm/llvm-project/commit/e223485c9b38a5579991b8cebb
> 6a200153eee245
>
> which encodes the number of arguments in the kCFI preamble's register.
>
> Using this register<->arity mapping, have the FineIBT preamble CALL
> into a stub clobbering the relevant argument registers in the
> speculative case.
>
> (This is where Scott goes and gives more details...)
Scott, could you give a blurb here? Would the below cover things?
The basic setup, for 1 argument, is something like:
__bhi_args_1:
jne .Lud
cmovne %r10, %rdi
ret
int3
__cfi_foo:
endbr
subl $hash, %r10d
call __bhi_args_1
foo:
osp nop3
...
such that when speculation of an indirect call is maliciously steered here from a non-matching site, the hash check (__cfi_foo's SUB) will not match, resulting in !ZF and non-zero R10. Subsequently the __bhi_args stub will either hit #UD exception, which kills speculation, or when steered wrong, hit the cmovne, which will then clobber the argument register RDI with whatever non-zero garbage sits in R10. Making it much harder to control whatever foo normally does with its input argument.
Additionally, CFI hashes are randomized at boot, making it much harder still to predict/control the non-zero value.
^ permalink raw reply [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/ibt: Optimize fineibt-bhi arity 1 case
2025-02-24 12:37 ` [PATCH v4 10/10] x86/ibt: Optimize fineibt-bhi arity 1 case Peter Zijlstra
@ 2025-02-26 10:54 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/ibt: Optimize the " tip-bot2 for Peter Zijlstra
2025-02-26 12:54 ` tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 10:54 UTC (permalink / raw)
To: linux-tip-commits
Cc: Scott Constable, Peter Zijlstra (Intel), Kees Cook, x86,
linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: af908171aed7b0a7f6376f3ee6c53f40c84ae494
Gitweb: https://git.kernel.org/tip/af908171aed7b0a7f6376f3ee6c53f40c84ae494
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:13 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 26 Feb 2025 11:41:56 +01:00
x86/ibt: Optimize fineibt-bhi arity 1 case
Saves a CALL to an out-of-line thunk for the common case of 1
argument.
Suggested-by: Scott Constable <scott.d.constable@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.927885784@infradead.org
---
arch/x86/include/asm/ibt.h | 4 ++-
arch/x86/kernel/alternative.c | 59 ++++++++++++++++++++++++++++------
2 files changed, 54 insertions(+), 9 deletions(-)
diff --git a/arch/x86/include/asm/ibt.h b/arch/x86/include/asm/ibt.h
index f0ca5c0..9423a29 100644
--- a/arch/x86/include/asm/ibt.h
+++ b/arch/x86/include/asm/ibt.h
@@ -70,6 +70,10 @@ static inline bool __is_endbr(u32 val)
if (val == gen_endbr_poison())
return true;
+ /* See cfi_fineibt_bhi_preamble() */
+ if (IS_ENABLED(CONFIG_FINEIBT_BHI) && val == 0x001f0ff5)
+ return true;
+
val &= ~0x01000000U; /* ENDBR32 -> ENDBR64 */
return val == gen_endbr();
}
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 93dccb2..8d8871a 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1307,6 +1307,53 @@ static int cfi_rand_preamble(s32 *start, s32 *end)
return 0;
}
+static void cfi_fineibt_bhi_preamble(void *addr, int arity)
+{
+ if (!arity)
+ return;
+
+ if (!cfi_warn && arity == 1) {
+ /*
+ * Crazy scheme to allow arity-1 inline:
+ *
+ * __cfi_foo:
+ * 0: f3 0f 1e fa endbr64
+ * 4: 41 81 <ea> 78 56 34 12 sub 0x12345678, %r10d
+ * b: 49 0f 45 fa cmovne %r10, %rdi
+ * f: 75 f5 jne __cfi_foo+6
+ * 11: 0f 1f 00 nopl (%rax)
+ *
+ * Code that direct calls to foo()+0, decodes the tail end as:
+ *
+ * foo:
+ * 0: f5 cmc
+ * 1: 0f 1f 00 nopl (%rax)
+ *
+ * which clobbers CF, but does not affect anything ABI
+ * wise.
+ *
+ * Notably, this scheme is incompatible with permissive CFI
+ * because the CMOVcc is unconditional and RDI will have been
+ * clobbered.
+ */
+ const u8 magic[9] = {
+ 0x49, 0x0f, 0x45, 0xfa,
+ 0x75, 0xf5,
+ BYTES_NOP3,
+ };
+
+ text_poke_early(addr + fineibt_preamble_bhi, magic, 9);
+
+ return;
+ }
+
+ text_poke_early(addr + fineibt_preamble_bhi,
+ text_gen_insn(CALL_INSN_OPCODE,
+ addr + fineibt_preamble_bhi,
+ __bhi_args[arity]),
+ CALL_INSN_SIZE);
+}
+
static int cfi_rewrite_preamble(s32 *start, s32 *end)
{
s32 *s;
@@ -1337,14 +1384,8 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
"kCFI preamble has wrong register at: %pS %*ph\n",
addr, 5, addr);
- if (!cfi_bhi || !arity)
- continue;
-
- text_poke_early(addr + fineibt_preamble_bhi,
- text_gen_insn(CALL_INSN_OPCODE,
- addr + fineibt_preamble_bhi,
- __bhi_args[arity]),
- CALL_INSN_SIZE);
+ if (cfi_bhi)
+ cfi_fineibt_bhi_preamble(addr, arity);
}
return 0;
@@ -1357,7 +1398,7 @@ static void cfi_rewrite_endbr(s32 *start, s32 *end)
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
- if (!is_endbr(addr + 16))
+ if (!exact_endbr(addr + 16))
continue;
poison_endbr(addr + 16);
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/ibt: Implement FineIBT-BHI mitigation
2025-02-24 12:37 ` [PATCH v4 09/10] x86/ibt: Implement FineIBT-BHI mitigation Peter Zijlstra
2025-02-25 9:12 ` Peter Zijlstra
@ 2025-02-26 10:54 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:54 ` tip-bot2 for Peter Zijlstra
3 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 10:54 UTC (permalink / raw)
To: linux-tip-commits
Cc: Scott Constable, Peter Zijlstra (Intel), Kees Cook, x86,
linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: 106a97384748b3cc7a42ea1598bd8193c6e2a2a0
Gitweb: https://git.kernel.org/tip/106a97384748b3cc7a42ea1598bd8193c6e2a2a0
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:12 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 26 Feb 2025 11:41:55 +01:00
x86/ibt: Implement FineIBT-BHI mitigation
While WAIT_FOR_ENDBR is specified to be a full speculation stop; it
has been shown that some implementations are 'leaky' to such an extend
that speculation can escape even the FineIBT preamble.
To deal with this, add additional hardening to the FineIBT preamble.
Notably, using a new LLVM feature:
https://github.com/llvm/llvm-project/commit/e223485c9b38a5579991b8cebb6a200153eee245
which encodes the number of arguments in the kCFI preamble's register.
Using this register<->arity mapping, have the FineIBT preamble CALL
into a stub clobbering the relevant argument registers in the
speculative case.
Scott sayeth thusly:
Microarchitectural attacks such as Branch History Injection (BHI) and
Intra-mode Branch Target Injection (IMBTI) [1] can cause an indirect
call to mispredict to an adversary-influenced target within the same
hardware domain (e.g., within the kernel). Instructions at the
mispredicted target may execute speculatively and potentially expose
kernel data (e.g., to a user-mode adversary) through a
microarchitectural covert channel such as CPU cache state.
CET-IBT [2] is a coarse-grained control-flow integrity (CFI) ISA
extension that enforces that each indirect call (or indirect jump)
must land on an ENDBR (end branch) instruction, even speculatively*.
FineIBT is a software technique that refines CET-IBT by associating
each function type with a 32-bit hash and enforcing (at the callee)
that the hash of the caller's function pointer type matches the hash
of the callee's function type. However, recent research [3] has
demonstrated that the conditional branch that enforces FineIBT's hash
check can be coerced to mispredict, potentially allowing an adversary
to speculatively bypass the hash check:
__cfi_foo:
ENDBR64
SUB R10d, 0x01234567
JZ foo # Even if the hash check fails and ZF=0, this branch could still mispredict as taken
UD2
foo:
...
The techniques demonstrated in [3] require the attacker to be able to
control the contents of at least one live register at the mispredicted
target. Therefore, this patch set introduces a sequence of CMOV
instructions at each indirect-callable target that poisons every live
register with data that the attacker cannot control whenever the
FineIBT hash check fails, thus mitigating any potential attack.
The security provided by this scheme has been discussed in detail on
an earlier thread [4].
[1] https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/branch-history-injection.html
[2] Intel Software Developer's Manual, Volume 1, Chapter 18
[3] https://www.vusec.net/projects/native-bhi/
[4] https://lore.kernel.org/lkml/20240927194925.707462984@infradead.org/
*There are some caveats for certain processors, see [1] for more info
Suggested-by: Scott Constable <scott.d.constable@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.820402212@infradead.org
---
Makefile | 3 +-
arch/x86/Kconfig | 8 ++-
arch/x86/include/asm/cfi.h | 6 ++-
arch/x86/kernel/alternative.c | 107 +++++++++++++++++++++++++++++----
arch/x86/net/bpf_jit_comp.c | 29 ++++++---
5 files changed, 134 insertions(+), 19 deletions(-)
diff --git a/Makefile b/Makefile
index 96407c1..f19431f 100644
--- a/Makefile
+++ b/Makefile
@@ -1014,6 +1014,9 @@ CC_FLAGS_CFI := -fsanitize=kcfi
ifdef CONFIG_CFI_ICALL_NORMALIZE_INTEGERS
CC_FLAGS_CFI += -fsanitize-cfi-icall-experimental-normalize-integers
endif
+ifdef CONFIG_FINEIBT_BHI
+ CC_FLAGS_CFI += -fsanitize-kcfi-arity
+endif
ifdef CONFIG_RUST
# Always pass -Zsanitizer-cfi-normalize-integers as CONFIG_RUST selects
# CONFIG_CFI_ICALL_NORMALIZE_INTEGERS.
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index c4175f4..5c27726 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2473,6 +2473,10 @@ config CC_HAS_RETURN_THUNK
config CC_HAS_ENTRY_PADDING
def_bool $(cc-option,-fpatchable-function-entry=16,16)
+config CC_HAS_KCFI_ARITY
+ def_bool $(cc-option,-fsanitize=kcfi -fsanitize-kcfi-arity)
+ depends on CC_IS_CLANG && !RUST
+
config FUNCTION_PADDING_CFI
int
default 59 if FUNCTION_ALIGNMENT_64B
@@ -2498,6 +2502,10 @@ config FINEIBT
depends on X86_KERNEL_IBT && CFI_CLANG && MITIGATION_RETPOLINE
select CALL_PADDING
+config FINEIBT_BHI
+ def_bool y
+ depends on FINEIBT && CC_HAS_KCFI_ARITY
+
config HAVE_CALL_THUNKS
def_bool y
depends on CC_HAS_ENTRY_PADDING && MITIGATION_RETHUNK && OBJTOOL
diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h
index 7c15c4b..2f6a01f 100644
--- a/arch/x86/include/asm/cfi.h
+++ b/arch/x86/include/asm/cfi.h
@@ -100,6 +100,7 @@ enum cfi_mode {
};
extern enum cfi_mode cfi_mode;
+extern bool cfi_bhi;
typedef u8 bhi_thunk[32];
extern bhi_thunk __bhi_args[];
@@ -129,6 +130,7 @@ static inline int cfi_get_offset(void)
#define cfi_get_offset cfi_get_offset
extern u32 cfi_get_func_hash(void *func);
+extern int cfi_get_func_arity(void *func);
#ifdef CONFIG_FINEIBT
extern bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type);
@@ -152,6 +154,10 @@ static inline u32 cfi_get_func_hash(void *func)
{
return 0;
}
+static inline int cfi_get_func_arity(void *func)
+{
+ return 0;
+}
#endif /* CONFIG_CFI_CLANG */
#if HAS_KERNEL_IBT == 1
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 2bb5ba5..93dccb2 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -932,6 +932,7 @@ void __init_or_module apply_seal_endbr(s32 *start, s32 *end) { }
#endif
enum cfi_mode cfi_mode __ro_after_init = __CFI_DEFAULT;
+bool cfi_bhi __ro_after_init = false;
#ifdef CONFIG_CFI_CLANG
struct bpf_insn;
@@ -992,6 +993,21 @@ u32 cfi_get_func_hash(void *func)
return hash;
}
+
+int cfi_get_func_arity(void *func)
+{
+ bhi_thunk *target;
+ s32 disp;
+
+ if (cfi_mode != CFI_FINEIBT && !cfi_bhi)
+ return 0;
+
+ if (get_kernel_nofault(disp, func - 4))
+ return 0;
+
+ target = func + disp;
+ return target - __bhi_args;
+}
#endif
#ifdef CONFIG_FINEIBT
@@ -1049,6 +1065,12 @@ static __init int cfi_parse_cmdline(char *str)
} else {
pr_err("Ignoring paranoid; depends on fineibt.\n");
}
+ } else if (!strcmp(str, "bhi")) {
+ if (cfi_mode == CFI_FINEIBT) {
+ cfi_bhi = true;
+ } else {
+ pr_err("Ignoring bhi; depends on fineibt.\n");
+ }
} else {
pr_err("Ignoring unknown cfi option (%s).", str);
}
@@ -1101,6 +1123,7 @@ asm( ".pushsection .rodata \n"
"fineibt_preamble_start: \n"
" endbr64 \n"
" subl $0x12345678, %r10d \n"
+ "fineibt_preamble_bhi: \n"
" jne fineibt_preamble_start+6 \n"
ASM_NOP3
"fineibt_preamble_end: \n"
@@ -1108,9 +1131,11 @@ asm( ".pushsection .rodata \n"
);
extern u8 fineibt_preamble_start[];
+extern u8 fineibt_preamble_bhi[];
extern u8 fineibt_preamble_end[];
#define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start)
+#define fineibt_preamble_bhi (fineibt_preamble_bhi - fineibt_preamble_start)
#define fineibt_preamble_ud 6
#define fineibt_preamble_hash 7
@@ -1183,13 +1208,16 @@ extern u8 fineibt_paranoid_end[];
#define fineibt_paranoid_ind (fineibt_paranoid_ind - fineibt_paranoid_start)
#define fineibt_paranoid_ud 0xd
-static u32 decode_preamble_hash(void *addr)
+static u32 decode_preamble_hash(void *addr, int *reg)
{
u8 *p = addr;
- /* b8 78 56 34 12 mov $0x12345678,%eax */
- if (p[0] == 0xb8)
+ /* b8+reg 78 56 34 12 movl $0x12345678,\reg */
+ if (p[0] >= 0xb8 && p[0] < 0xc0) {
+ if (reg)
+ *reg = p[0] - 0xb8;
return *(u32 *)(addr + 1);
+ }
return 0; /* invalid hash value */
}
@@ -1198,11 +1226,11 @@ static u32 decode_caller_hash(void *addr)
{
u8 *p = addr;
- /* 41 ba 78 56 34 12 mov $0x12345678,%r10d */
+ /* 41 ba 88 a9 cb ed mov $(-0x12345678),%r10d */
if (p[0] == 0x41 && p[1] == 0xba)
return -*(u32 *)(addr + 2);
- /* e8 0c 78 56 34 12 jmp.d8 +12 */
+ /* e8 0c 88 a9 cb ed jmp.d8 +12 */
if (p[0] == JMP8_INSN_OPCODE && p[1] == fineibt_caller_jmp)
return -*(u32 *)(addr + 2);
@@ -1267,7 +1295,7 @@ static int cfi_rand_preamble(s32 *start, s32 *end)
void *addr = (void *)s + *s;
u32 hash;
- hash = decode_preamble_hash(addr);
+ hash = decode_preamble_hash(addr, NULL);
if (WARN(!hash, "no CFI hash found at: %pS %px %*ph\n",
addr, addr, 5, addr))
return -EINVAL;
@@ -1285,6 +1313,7 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ int arity;
u32 hash;
/*
@@ -1295,7 +1324,7 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
if (!is_endbr(addr + 16))
continue;
- hash = decode_preamble_hash(addr);
+ hash = decode_preamble_hash(addr, &arity);
if (WARN(!hash, "no CFI hash found at: %pS %px %*ph\n",
addr, addr, 5, addr))
return -EINVAL;
@@ -1303,6 +1332,19 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
text_poke_early(addr, fineibt_preamble_start, fineibt_preamble_size);
WARN_ON(*(u32 *)(addr + fineibt_preamble_hash) != 0x12345678);
text_poke_early(addr + fineibt_preamble_hash, &hash, 4);
+
+ WARN_ONCE(!IS_ENABLED(CONFIG_FINEIBT_BHI) && arity,
+ "kCFI preamble has wrong register at: %pS %*ph\n",
+ addr, 5, addr);
+
+ if (!cfi_bhi || !arity)
+ continue;
+
+ text_poke_early(addr + fineibt_preamble_bhi,
+ text_gen_insn(CALL_INSN_OPCODE,
+ addr + fineibt_preamble_bhi,
+ __bhi_args[arity]),
+ CALL_INSN_SIZE);
}
return 0;
@@ -1470,8 +1512,9 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
cfi_rewrite_endbr(start_cfi, end_cfi);
if (builtin) {
- pr_info("Using %sFineIBT CFI\n",
- cfi_paranoid ? "paranoid " : "");
+ pr_info("Using %sFineIBT%s CFI\n",
+ cfi_paranoid ? "paranoid " : "",
+ cfi_bhi ? "+BHI" : "");
}
return;
@@ -1522,7 +1565,7 @@ static void poison_cfi(void *addr)
/*
* kCFI prefix should start with a valid hash.
*/
- if (!decode_preamble_hash(addr))
+ if (!decode_preamble_hash(addr, NULL))
break;
/*
@@ -1571,6 +1614,47 @@ Efault:
}
/*
+ * regs->ip points to one of the UD2 in __bhi_args[].
+ */
+static bool decode_fineibt_bhi(struct pt_regs *regs, unsigned long *target, u32 *type)
+{
+ unsigned long addr;
+ u32 hash;
+
+ if (!cfi_bhi)
+ return false;
+
+ if (regs->ip < (unsigned long)__bhi_args ||
+ regs->ip >= (unsigned long)__bhi_args_end)
+ return false;
+
+ /*
+ * Fetch the return address from the stack, this points to the
+ * FineIBT preamble. Since the CALL instruction is in the 5 last
+ * bytes of the preamble, the return address is in fact the target
+ * address.
+ */
+ __get_kernel_nofault(&addr, regs->sp, unsigned long, Efault);
+ *target = addr;
+
+ addr -= fineibt_preamble_size;
+ if (!exact_endbr((void *)addr))
+ return false;
+
+ __get_kernel_nofault(&hash, addr + fineibt_preamble_hash, u32, Efault);
+ *type = (u32)regs->r10 + hash;
+
+ /*
+ * The UD2 sites are constructed with a RET immediately following,
+ * as such the non-fatal case can use the regular fixup.
+ */
+ return true;
+
+Efault:
+ return false;
+}
+
+/*
* regs->ip points to a LOCK Jcc.d8 instruction from the fineibt_paranoid_start[]
* sequence.
*/
@@ -1601,6 +1685,9 @@ bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
if (decode_fineibt_paranoid(regs, target, type))
return true;
+ if (decode_fineibt_bhi(regs, target, type))
+ return true;
+
return decode_fineibt_preamble(regs, target, type);
}
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index ce033e6..72776dc 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -410,15 +410,20 @@ static void emit_nops(u8 **pprog, int len)
* Emit the various CFI preambles, see asm/cfi.h and the comments about FineIBT
* in arch/x86/kernel/alternative.c
*/
+static int emit_call(u8 **prog, void *func, void *ip);
-static void emit_fineibt(u8 **pprog, u32 hash)
+static void emit_fineibt(u8 **pprog, u8 *ip, u32 hash, int arity)
{
u8 *prog = *pprog;
EMIT_ENDBR();
EMIT3_off32(0x41, 0x81, 0xea, hash); /* subl $hash, %r10d */
- EMIT2(0x75, 0xf9); /* jne.d8 .-7 */
- EMIT3(0x0f, 0x1f, 0x00); /* nop3 */
+ if (cfi_bhi) {
+ emit_call(&prog, __bhi_args[arity], ip + 11);
+ } else {
+ EMIT2(0x75, 0xf9); /* jne.d8 .-7 */
+ EMIT3(0x0f, 0x1f, 0x00); /* nop3 */
+ }
EMIT_ENDBR_POISON();
*pprog = prog;
@@ -447,13 +452,13 @@ static void emit_kcfi(u8 **pprog, u32 hash)
*pprog = prog;
}
-static void emit_cfi(u8 **pprog, u32 hash)
+static void emit_cfi(u8 **pprog, u8 *ip, u32 hash, int arity)
{
u8 *prog = *pprog;
switch (cfi_mode) {
case CFI_FINEIBT:
- emit_fineibt(&prog, hash);
+ emit_fineibt(&prog, ip, hash, arity);
break;
case CFI_KCFI:
@@ -504,13 +509,17 @@ static void emit_prologue_tail_call(u8 **pprog, bool is_subprog)
* bpf_tail_call helper will skip the first X86_TAIL_CALL_OFFSET bytes
* while jumping to another program
*/
-static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf,
+static void emit_prologue(u8 **pprog, u8 *ip, u32 stack_depth, bool ebpf_from_cbpf,
bool tail_call_reachable, bool is_subprog,
bool is_exception_cb)
{
u8 *prog = *pprog;
- emit_cfi(&prog, is_subprog ? cfi_bpf_subprog_hash : cfi_bpf_hash);
+ if (is_subprog) {
+ emit_cfi(&prog, ip, cfi_bpf_subprog_hash, 5);
+ } else {
+ emit_cfi(&prog, ip, cfi_bpf_hash, 1);
+ }
/* BPF trampoline can be made to work without these nops,
* but let's waste 5 bytes for now and optimize later
*/
@@ -1479,7 +1488,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
detect_reg_usage(insn, insn_cnt, callee_regs_used);
- emit_prologue(&prog, stack_depth,
+ emit_prologue(&prog, image, stack_depth,
bpf_prog_was_classic(bpf_prog), tail_call_reachable,
bpf_is_subprog(bpf_prog), bpf_prog->aux->exception_cb);
/* Exception callback will clobber callee regs for its own use, and
@@ -3046,7 +3055,9 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
/*
* Indirect call for bpf_struct_ops
*/
- emit_cfi(&prog, cfi_get_func_hash(func_addr));
+ emit_cfi(&prog, image,
+ cfi_get_func_hash(func_addr),
+ cfi_get_func_arity(func_addr));
} else {
/*
* Direct-call fentry stub, as such it needs accounting for the
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86: BHI stubs
2025-02-24 12:37 ` [PATCH v4 08/10] x86: BHI stubs Peter Zijlstra
2025-02-24 19:01 ` Kees Cook
@ 2025-02-26 10:54 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/bhi: Add " tip-bot2 for Peter Zijlstra
2025-02-26 12:54 ` tip-bot2 for Peter Zijlstra
3 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 10:54 UTC (permalink / raw)
To: linux-tip-commits; +Cc: Peter Zijlstra (Intel), Kees Cook, x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: 53f12687ab00414965a96768bbf09a9c8485a669
Gitweb: https://git.kernel.org/tip/53f12687ab00414965a96768bbf09a9c8485a669
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:11 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 26 Feb 2025 11:41:55 +01:00
x86: BHI stubs
Add an array of code thunks, to be called from the FineIBT preamble,
clobbering the first 'n' argument registers for speculative execution.
Notably the 0th entry will clobber no argument registers and will never
be used, it exists so the array can be naturally indexed, while the 7th
entry will clobber all the 6 argument registers and also RSP in order to
mess up stack based arguments.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.717378681@infradead.org
---
arch/x86/include/asm/cfi.h | 4 +-
arch/x86/lib/Makefile | 3 +-
arch/x86/lib/bhi.S | 146 ++++++++++++++++++++++++++++++++++++-
3 files changed, 152 insertions(+), 1 deletion(-)
create mode 100644 arch/x86/lib/bhi.S
diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h
index 7dd5ab2..7c15c4b 100644
--- a/arch/x86/include/asm/cfi.h
+++ b/arch/x86/include/asm/cfi.h
@@ -101,6 +101,10 @@ enum cfi_mode {
extern enum cfi_mode cfi_mode;
+typedef u8 bhi_thunk[32];
+extern bhi_thunk __bhi_args[];
+extern bhi_thunk __bhi_args_end[];
+
struct pt_regs;
#ifdef CONFIG_CFI_CLANG
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 8a59c61..f453507 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -66,5 +66,6 @@ endif
lib-y += clear_page_64.o copy_page_64.o
lib-y += memmove_64.o memset_64.o
lib-y += copy_user_64.o copy_user_uncached_64.o
- lib-y += cmpxchg16b_emu.o
+ lib-y += cmpxchg16b_emu.o
+ lib-y += bhi.o
endif
diff --git a/arch/x86/lib/bhi.S b/arch/x86/lib/bhi.S
new file mode 100644
index 0000000..421e307
--- /dev/null
+++ b/arch/x86/lib/bhi.S
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/linkage.h>
+#include <asm/unwind_hints.h>
+#include <asm/nospec-branch.h>
+
+/*
+ * Notably, the FineIBT preamble calling these will have ZF set and r10 zero.
+ *
+ * The very last element is in fact larger than 32 bytes, but since its the
+ * last element, this does not matter,
+ *
+ * There are 2 #UD sites, located between 0,1-2,3 and 4,5-6,7 such that they
+ * can be reached using Jcc.d8, these elements (1 and 5) have sufficiently
+ * big alignment holes for this to not stagger the array.
+ */
+
+.pushsection .noinstr.text, "ax"
+
+ .align 32
+SYM_CODE_START(__bhi_args)
+
+#ifdef CONFIG_FINEIBT_BHI
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_0, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_1, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ cmovne %r10, %rdi
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 8
+ ANNOTATE_REACHABLE
+.Lud_1: ud2
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_2, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_3, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_4, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_5, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ cmovne %r10, %r8
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 8
+ ANNOTATE_REACHABLE
+.Lud_2: ud2
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_6, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ cmovne %r10, %r8
+ cmovne %r10, %r9
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_7, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ cmovne %r10, %r8
+ cmovne %r10, %r9
+ cmovne %r10, %rsp
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+#endif /* CONFIG_FINEIBT_BHI */
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_end, SYM_L_GLOBAL)
+ ANNOTATE_NOENDBR
+SYM_CODE_END(__bhi_args)
+
+.popsection
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/traps: Decode LOCK Jcc.d8 #UD
2025-02-24 12:37 ` [PATCH v4 06/10] x86/traps: Decode LOCK Jcc.d8 #UD Peter Zijlstra
2025-02-24 21:46 ` David Laight
@ 2025-02-26 10:54 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/traps: Decode LOCK Jcc.d8 as #UD tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 10:54 UTC (permalink / raw)
To: linux-tip-commits; +Cc: Peter Zijlstra (Intel), Kees Cook, x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: e874854d308841f2383ee3d04f0438f56ddddaaf
Gitweb: https://git.kernel.org/tip/e874854d308841f2383ee3d04f0438f56ddddaaf
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:09 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 26 Feb 2025 11:41:55 +01:00
x86/traps: Decode LOCK Jcc.d8 #UD
Because overlapping code sequences are all the rage.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.486463917@infradead.org
---
arch/x86/include/asm/bug.h | 2 ++
arch/x86/kernel/traps.c | 26 +++++++++++++++++++++++---
2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h
index bc8a2ca..f0e9acf 100644
--- a/arch/x86/include/asm/bug.h
+++ b/arch/x86/include/asm/bug.h
@@ -17,6 +17,7 @@
* In clang we have UD1s reporting UBSAN failures on X86, 64 and 32bit.
*/
#define INSN_ASOP 0x67
+#define INSN_LOCK 0xf0
#define OPCODE_ESCAPE 0x0f
#define SECOND_BYTE_OPCODE_UD1 0xb9
#define SECOND_BYTE_OPCODE_UD2 0x0b
@@ -26,6 +27,7 @@
#define BUG_UD1 0xfffd
#define BUG_UD1_UBSAN 0xfffc
#define BUG_EA 0xffea
+#define BUG_LOCK 0xfff0
#ifdef CONFIG_GENERIC_BUG
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index c169f3b..f4263cb 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -97,6 +97,7 @@ __always_inline int is_valid_bugaddr(unsigned long addr)
* If it's a UD1, further decode to determine its use:
*
* FineIBT: ea (bad)
+ * FineIBT: f0 75 f9 lock jne . - 6
* UBSan{0}: 67 0f b9 00 ud1 (%eax),%eax
* UBSan{10}: 67 0f b9 40 10 ud1 0x10(%eax),%eax
* static_call: 0f b9 cc ud1 %esp,%ecx
@@ -106,6 +107,7 @@ __always_inline int is_valid_bugaddr(unsigned long addr)
__always_inline int decode_bug(unsigned long addr, s32 *imm, int *len)
{
unsigned long start = addr;
+ bool lock = false;
u8 v;
if (addr < TASK_SIZE_MAX)
@@ -114,12 +116,29 @@ __always_inline int decode_bug(unsigned long addr, s32 *imm, int *len)
v = *(u8 *)(addr++);
if (v == INSN_ASOP)
v = *(u8 *)(addr++);
- if (v == 0xea) {
+
+ if (v == INSN_LOCK) {
+ lock = true;
+ v = *(u8 *)(addr++);
+ }
+
+ switch (v) {
+ case 0x70 ... 0x7f: /* Jcc.d8 */
+ addr += 1; /* d8 */
+ *len = addr - start;
+ WARN_ON_ONCE(!lock);
+ return BUG_LOCK;
+
+ case 0xea:
*len = addr - start;
return BUG_EA;
- }
- if (v != OPCODE_ESCAPE)
+
+ case OPCODE_ESCAPE:
+ break;
+
+ default:
return BUG_NONE;
+ }
v = *(u8 *)(addr++);
if (v == SECOND_BYTE_OPCODE_UD2) {
@@ -322,6 +341,7 @@ static noinstr bool handle_bug(struct pt_regs *regs)
fallthrough;
case BUG_EA:
+ case BUG_LOCK:
if (handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) {
handled = true;
break;
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/ibt: Add paranoid FineIBT mode
2025-02-24 12:37 ` [PATCH v4 07/10] x86/ibt: Add paranoid FineIBT mode Peter Zijlstra
2025-02-24 19:00 ` Kees Cook
@ 2025-02-26 10:54 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 10:54 UTC (permalink / raw)
To: linux-tip-commits
Cc: Jennifer Miller, Peter Zijlstra (Intel), Kees Cook, x86,
linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: 3b920ee30ac68e6b040d37b9205f0acc074a0d9b
Gitweb: https://git.kernel.org/tip/3b920ee30ac68e6b040d37b9205f0acc074a0d9b
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:10 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 26 Feb 2025 11:41:55 +01:00
x86/ibt: Add paranoid FineIBT mode
Due to concerns about circumvention attacks against FineIBT on 'naked'
ENDBR, add an additional caller side hash check to FineIBT. This
should make it impossible to pivot over such a 'naked' ENDBR
instruction at the cost of an additional load.
The specific pivot reported was against the SYSCALL entry site and
FRED will have all those holes fixed up.
https://lore.kernel.org/linux-hardening/Z60NwR4w%2F28Z7XUa@ubun/
This specific fineibt_paranoid_start[] sequence was concocted by
Scott.
Reported-by: Jennifer Miller <jmill@asu.edu>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.598033084@infradead.org
---
arch/x86/kernel/alternative.c | 144 +++++++++++++++++++++++++++++++--
1 file changed, 138 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 599f218..2bb5ba5 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -741,6 +741,11 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
op2 = insn.opcode.bytes[1];
switch (op1) {
+ case 0x70 ... 0x7f: /* Jcc.d8 */
+ /* See cfi_paranoid. */
+ WARN_ON_ONCE(cfi_mode != CFI_FINEIBT);
+ continue;
+
case CALL_INSN_OPCODE:
case JMP32_INSN_OPCODE:
break;
@@ -994,6 +999,8 @@ u32 cfi_get_func_hash(void *func)
static bool cfi_rand __ro_after_init = true;
static u32 cfi_seed __ro_after_init;
+static bool cfi_paranoid __ro_after_init = false;
+
/*
* Re-hash the CFI hash with a boot-time seed while making sure the result is
* not a valid ENDBR instruction.
@@ -1036,6 +1043,12 @@ static __init int cfi_parse_cmdline(char *str)
} else if (!strcmp(str, "warn")) {
pr_alert("CFI mismatch non-fatal!\n");
cfi_warn = true;
+ } else if (!strcmp(str, "paranoid")) {
+ if (cfi_mode == CFI_FINEIBT) {
+ cfi_paranoid = true;
+ } else {
+ pr_err("Ignoring paranoid; depends on fineibt.\n");
+ }
} else {
pr_err("Ignoring unknown cfi option (%s).", str);
}
@@ -1124,6 +1137,52 @@ extern u8 fineibt_caller_end[];
#define fineibt_caller_jmp (fineibt_caller_size - 2)
+/*
+ * Since FineIBT does hash validation on the callee side it is prone to
+ * circumvention attacks where a 'naked' ENDBR instruction exists that
+ * is not part of the fineibt_preamble sequence.
+ *
+ * Notably the x86 entry points must be ENDBR and equally cannot be
+ * fineibt_preamble.
+ *
+ * The fineibt_paranoid caller sequence adds additional caller side
+ * hash validation. This stops such circumvention attacks dead, but at the cost
+ * of adding a load.
+ *
+ * <fineibt_paranoid_start>:
+ * 0: 41 ba 78 56 34 12 mov $0x12345678, %r10d
+ * 6: 45 3b 53 f7 cmp -0x9(%r11), %r10d
+ * a: 4d 8d 5b <f0> lea -0x10(%r11), %r11
+ * e: 75 fd jne d <fineibt_paranoid_start+0xd>
+ * 10: 41 ff d3 call *%r11
+ * 13: 90 nop
+ *
+ * Notably LEA does not modify flags and can be reordered with the CMP,
+ * avoiding a dependency. Again, using a non-taken (backwards) branch
+ * for the failure case, abusing LEA's immediate 0xf0 as LOCK prefix for the
+ * Jcc.d8, causing #UD.
+ */
+asm( ".pushsection .rodata \n"
+ "fineibt_paranoid_start: \n"
+ " movl $0x12345678, %r10d \n"
+ " cmpl -9(%r11), %r10d \n"
+ " lea -0x10(%r11), %r11 \n"
+ " jne fineibt_paranoid_start+0xd \n"
+ "fineibt_paranoid_ind: \n"
+ " call *%r11 \n"
+ " nop \n"
+ "fineibt_paranoid_end: \n"
+ ".popsection \n"
+);
+
+extern u8 fineibt_paranoid_start[];
+extern u8 fineibt_paranoid_ind[];
+extern u8 fineibt_paranoid_end[];
+
+#define fineibt_paranoid_size (fineibt_paranoid_end - fineibt_paranoid_start)
+#define fineibt_paranoid_ind (fineibt_paranoid_ind - fineibt_paranoid_start)
+#define fineibt_paranoid_ud 0xd
+
static u32 decode_preamble_hash(void *addr)
{
u8 *p = addr;
@@ -1287,18 +1346,48 @@ static int cfi_rewrite_callers(s32 *start, s32 *end)
{
s32 *s;
+ BUG_ON(fineibt_paranoid_size != 20);
+
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ struct insn insn;
+ u8 bytes[20];
u32 hash;
+ int ret;
+ u8 op;
addr -= fineibt_caller_size;
hash = decode_caller_hash(addr);
- if (hash) {
+ if (!hash)
+ continue;
+
+ if (!cfi_paranoid) {
text_poke_early(addr, fineibt_caller_start, fineibt_caller_size);
WARN_ON(*(u32 *)(addr + fineibt_caller_hash) != 0x12345678);
text_poke_early(addr + fineibt_caller_hash, &hash, 4);
+ /* rely on apply_retpolines() */
+ continue;
+ }
+
+ /* cfi_paranoid */
+ ret = insn_decode_kernel(&insn, addr + fineibt_caller_size);
+ if (WARN_ON_ONCE(ret < 0))
+ continue;
+
+ op = insn.opcode.bytes[0];
+ if (op != CALL_INSN_OPCODE && op != JMP32_INSN_OPCODE) {
+ WARN_ON_ONCE(1);
+ continue;
}
- /* rely on apply_retpolines() */
+
+ memcpy(bytes, fineibt_paranoid_start, fineibt_paranoid_size);
+ memcpy(bytes + fineibt_caller_hash, &hash, 4);
+
+ ret = emit_indirect(op, 11, bytes + fineibt_paranoid_ind);
+ if (WARN_ON_ONCE(ret != 3))
+ continue;
+
+ text_poke_early(addr, bytes, fineibt_paranoid_size);
}
return 0;
@@ -1315,8 +1404,15 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
if (cfi_mode == CFI_AUTO) {
cfi_mode = CFI_KCFI;
- if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT))
+ if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT)) {
+ /*
+ * FRED has much saner context on exception entry and
+ * is less easy to take advantage of.
+ */
+ if (!cpu_feature_enabled(X86_FEATURE_FRED))
+ cfi_paranoid = true;
cfi_mode = CFI_FINEIBT;
+ }
}
/*
@@ -1373,8 +1469,10 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
/* now that nobody targets func()+0, remove ENDBR there */
cfi_rewrite_endbr(start_cfi, end_cfi);
- if (builtin)
- pr_info("Using FineIBT CFI\n");
+ if (builtin) {
+ pr_info("Using %sFineIBT CFI\n",
+ cfi_paranoid ? "paranoid " : "");
+ }
return;
default:
@@ -1447,7 +1545,7 @@ static void poison_cfi(void *addr)
* We check the preamble by checking for the ENDBR instruction relative to the
* 0xEA instruction.
*/
-bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
+static bool decode_fineibt_preamble(struct pt_regs *regs, unsigned long *target, u32 *type)
{
unsigned long addr = regs->ip - fineibt_preamble_ud;
u32 hash;
@@ -1472,6 +1570,40 @@ Efault:
return false;
}
+/*
+ * regs->ip points to a LOCK Jcc.d8 instruction from the fineibt_paranoid_start[]
+ * sequence.
+ */
+static bool decode_fineibt_paranoid(struct pt_regs *regs, unsigned long *target, u32 *type)
+{
+ unsigned long addr = regs->ip - fineibt_paranoid_ud;
+ u32 hash;
+
+ if (!cfi_paranoid || !is_cfi_trap(addr + fineibt_caller_size - LEN_UD2))
+ return false;
+
+ __get_kernel_nofault(&hash, addr + fineibt_caller_hash, u32, Efault);
+ *target = regs->r11 + fineibt_preamble_size;
+ *type = regs->r10;
+
+ /*
+ * Since the trapping instruction is the exact, but LOCK prefixed,
+ * Jcc.d8 that got us here, the normal fixup will work.
+ */
+ return true;
+
+Efault:
+ return false;
+}
+
+bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
+{
+ if (decode_fineibt_paranoid(regs, target, type))
+ return true;
+
+ return decode_fineibt_preamble(regs, target, type);
+}
+
#else
static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/ibt: Optimize FineIBT sequence
2025-02-24 12:37 ` [PATCH v4 05/10] x86/ibt: Optimize FineIBT sequence Peter Zijlstra
@ 2025-02-26 10:54 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/ibt: Optimize the FineIBT instruction sequence tip-bot2 for Peter Zijlstra
1 sibling, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 10:54 UTC (permalink / raw)
To: linux-tip-commits
Cc: Scott Constable, Peter Zijlstra (Intel), Kees Cook, x86,
linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: 7359ea8e1b7fbd5b98cb72a9f596ddf67f2dc33b
Gitweb: https://git.kernel.org/tip/7359ea8e1b7fbd5b98cb72a9f596ddf67f2dc33b
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:08 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 26 Feb 2025 11:41:54 +01:00
x86/ibt: Optimize FineIBT sequence
Scott notes that non-taken branches are faster. Abuse overlapping code
that traps instead of explicit UD2 instructions.
And LEA does not modify flags and will have less dependencies.
Suggested-by: Scott Constable <scott.d.constable@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.371942555@infradead.org
---
arch/x86/kernel/alternative.c | 61 ++++++++++++++++++++++------------
arch/x86/net/bpf_jit_comp.c | 5 +--
2 files changed, 42 insertions(+), 24 deletions(-)
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 1cc0e4d..599f218 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1053,9 +1053,9 @@ early_param("cfi", cfi_parse_cmdline);
* __cfi_\func: __cfi_\func:
* movl $0x12345678,%eax // 5 endbr64 // 4
* nop subl $0x12345678,%r10d // 7
- * nop jz 1f // 2
- * nop ud2 // 2
- * nop 1: nop // 1
+ * nop jne __cfi_\func+6 // 2
+ * nop nop3 // 3
+ * nop
* nop
* nop
* nop
@@ -1067,37 +1067,50 @@ early_param("cfi", cfi_parse_cmdline);
*
* caller: caller:
* movl $(-0x12345678),%r10d // 6 movl $0x12345678,%r10d // 6
- * addl $-15(%r11),%r10d // 4 sub $16,%r11 // 4
+ * addl $-15(%r11),%r10d // 4 lea -0x10(%r11),%r11 // 4
* je 1f // 2 nop4 // 4
* ud2 // 2
- * 1: call __x86_indirect_thunk_r11 // 5 call *%r11; nop2; // 5
+ * 1: cs call __x86_indirect_thunk_r11 // 6 call *%r11; nop3; // 6
*
*/
-asm( ".pushsection .rodata \n"
- "fineibt_preamble_start: \n"
- " endbr64 \n"
- " subl $0x12345678, %r10d \n"
- " je fineibt_preamble_end \n"
- "fineibt_preamble_ud2: \n"
- " ud2 \n"
- " nop \n"
- "fineibt_preamble_end: \n"
+/*
+ * <fineibt_preamble_start>:
+ * 0: f3 0f 1e fa endbr64
+ * 4: 41 81 <ea> 78 56 34 12 sub $0x12345678, %r10d
+ * b: 75 f9 jne 6 <fineibt_preamble_start+0x6>
+ * d: 0f 1f 00 nopl (%rax)
+ *
+ * Note that the JNE target is the 0xEA byte inside the SUB, this decodes as
+ * (bad) on x86_64 and raises #UD.
+ */
+asm( ".pushsection .rodata \n"
+ "fineibt_preamble_start: \n"
+ " endbr64 \n"
+ " subl $0x12345678, %r10d \n"
+ " jne fineibt_preamble_start+6 \n"
+ ASM_NOP3
+ "fineibt_preamble_end: \n"
".popsection\n"
);
extern u8 fineibt_preamble_start[];
-extern u8 fineibt_preamble_ud2[];
extern u8 fineibt_preamble_end[];
#define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start)
-#define fineibt_preamble_ud2 (fineibt_preamble_ud2 - fineibt_preamble_start)
+#define fineibt_preamble_ud 6
#define fineibt_preamble_hash 7
+/*
+ * <fineibt_caller_start>:
+ * 0: 41 ba 78 56 34 12 mov $0x12345678, %r10d
+ * 6: 4d 8d 5b f0 lea -0x10(%r11), %r11
+ * a: 0f 1f 40 00 nopl 0x0(%rax)
+ */
asm( ".pushsection .rodata \n"
"fineibt_caller_start: \n"
" movl $0x12345678, %r10d \n"
- " sub $16, %r11 \n"
+ " lea -0x10(%r11), %r11 \n"
ASM_NOP4
"fineibt_caller_end: \n"
".popsection \n"
@@ -1428,15 +1441,15 @@ static void poison_cfi(void *addr)
}
/*
- * regs->ip points to a UD2 instruction, return true and fill out target and
- * type when this UD2 is from a FineIBT preamble.
+ * When regs->ip points to a 0xEA byte in the FineIBT preamble,
+ * return true and fill out target and type.
*
* We check the preamble by checking for the ENDBR instruction relative to the
- * UD2 instruction.
+ * 0xEA instruction.
*/
bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
{
- unsigned long addr = regs->ip - fineibt_preamble_ud2;
+ unsigned long addr = regs->ip - fineibt_preamble_ud;
u32 hash;
if (!exact_endbr((void *)addr))
@@ -1447,6 +1460,12 @@ bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
__get_kernel_nofault(&hash, addr + fineibt_preamble_hash, u32, Efault);
*type = (u32)regs->r10 + hash;
+ /*
+ * Since regs->ip points to the middle of an instruction; it cannot
+ * continue with the normal fixup.
+ */
+ regs->ip = *target;
+
return true;
Efault:
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index f36508b..ce033e6 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -417,9 +417,8 @@ static void emit_fineibt(u8 **pprog, u32 hash)
EMIT_ENDBR();
EMIT3_off32(0x41, 0x81, 0xea, hash); /* subl $hash, %r10d */
- EMIT2(0x74, 0x07); /* jz.d8 +7 */
- EMIT2(0x0f, 0x0b); /* ud2 */
- EMIT1(0x90); /* nop */
+ EMIT2(0x75, 0xf9); /* jne.d8 .-7 */
+ EMIT3(0x0f, 0x1f, 0x00); /* nop3 */
EMIT_ENDBR_POISON();
*pprog = prog;
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/traps: Allow custom fixups in handle_bug()
2025-02-24 12:37 ` [PATCH v4 04/10] x86/traps: Allow custom fixups in handle_bug() Peter Zijlstra
2025-02-24 18:59 ` Kees Cook
@ 2025-02-26 10:54 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 10:54 UTC (permalink / raw)
To: linux-tip-commits; +Cc: Peter Zijlstra (Intel), Kees Cook, x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: 5d28fddb66e672e3183716a156cae04597599d3b
Gitweb: https://git.kernel.org/tip/5d28fddb66e672e3183716a156cae04597599d3b
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:07 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 26 Feb 2025 11:41:54 +01:00
x86/traps: Allow custom fixups in handle_bug()
The normal fixup in handle_bug() is simply continuing at the next
instruction. However upcomming patches make this the wrong thing, so
allow handlers (specifically handle_cfi_failure()) to over-ride
regs->ip.
The callchain is such that the fixup needs to be done before it is
determined if the exception is fatal, as such, revert any changes in
that case.
Additionally, have handle_cfi_failure() remember the regs->ip value it
starts with for reporting.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.275223080@infradead.org
---
arch/x86/kernel/cfi.c | 8 ++++----
arch/x86/kernel/traps.c | 16 +++++++++++++---
2 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/arch/x86/kernel/cfi.c b/arch/x86/kernel/cfi.c
index f6905be..77086cf 100644
--- a/arch/x86/kernel/cfi.c
+++ b/arch/x86/kernel/cfi.c
@@ -67,16 +67,16 @@ static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target,
*/
enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
{
- unsigned long target;
+ unsigned long target, addr = regs->ip;
u32 type;
switch (cfi_mode) {
case CFI_KCFI:
- if (!is_cfi_trap(regs->ip))
+ if (!is_cfi_trap(addr))
return BUG_TRAP_TYPE_NONE;
if (!decode_cfi_insn(regs, &target, &type))
- return report_cfi_failure_noaddr(regs, regs->ip);
+ return report_cfi_failure_noaddr(regs, addr);
break;
@@ -90,7 +90,7 @@ enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
return BUG_TRAP_TYPE_NONE;
}
- return report_cfi_failure(regs, regs->ip, &target, type);
+ return report_cfi_failure(regs, addr, &target, type);
}
/*
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index a02a51b..c169f3b 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -287,11 +287,12 @@ static inline void handle_invalid_op(struct pt_regs *regs)
static noinstr bool handle_bug(struct pt_regs *regs)
{
+ unsigned long addr = regs->ip;
bool handled = false;
int ud_type, ud_len;
s32 ud_imm;
- ud_type = decode_bug(regs->ip, &ud_imm, &ud_len);
+ ud_type = decode_bug(addr, &ud_imm, &ud_len);
if (ud_type == BUG_NONE)
return handled;
@@ -339,8 +340,17 @@ static noinstr bool handle_bug(struct pt_regs *regs)
break;
}
- if (handled)
- regs->ip += ud_len;
+ /*
+ * When continuing, and regs->ip hasn't changed, move it to the next
+ * instruction. When not continuing execution, restore the instruction
+ * pointer.
+ */
+ if (handled) {
+ if (regs->ip == addr)
+ regs->ip += ud_len;
+ } else {
+ regs->ip = addr;
+ }
if (regs->flags & X86_EFLAGS_IF)
raw_local_irq_disable();
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/ibt: Add exact_endbr() helper
2025-02-24 12:37 ` [PATCH v4 02/10] x86/ibt: Add exact_endbr() helper Peter Zijlstra
@ 2025-02-26 10:54 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
1 sibling, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 10:54 UTC (permalink / raw)
To: linux-tip-commits; +Cc: Peter Zijlstra (Intel), Kees Cook, x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: 1d60b295042d20f312de17d74076a74a0d13a32d
Gitweb: https://git.kernel.org/tip/1d60b295042d20f312de17d74076a74a0d13a32d
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:05 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 26 Feb 2025 11:41:53 +01:00
x86/ibt: Add exact_endbr() helper
For when we want to exactly match ENDBR, and not everything that we
can scribble it with.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.059556588@infradead.org
---
arch/x86/kernel/alternative.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 1142ebd..1cc0e4d 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -863,6 +863,17 @@ Efault:
return false;
}
+static __noendbr bool exact_endbr(u32 *val)
+{
+ u32 endbr;
+
+ __get_kernel_nofault(&endbr, val, u32, Efault);
+ return endbr == gen_endbr();
+
+Efault:
+ return false;
+}
+
static void poison_cfi(void *addr);
static void __init_or_module poison_endbr(void *addr)
@@ -1426,10 +1437,9 @@ static void poison_cfi(void *addr)
bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
{
unsigned long addr = regs->ip - fineibt_preamble_ud2;
- u32 endbr, hash;
+ u32 hash;
- __get_kernel_nofault(&endbr, addr, u32, Efault);
- if (endbr != gen_endbr())
+ if (!exact_endbr((void *)addr))
return false;
*target = addr + fineibt_preamble_size;
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/traps: Decode 0xEA #UD
2025-02-24 12:37 ` [PATCH v4 03/10] x86/traps: Decode 0xEA #UD Peter Zijlstra
2025-02-24 18:58 ` Kees Cook
@ 2025-02-26 10:54 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/traps: Decode 0xEA instructions as #UD tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 10:54 UTC (permalink / raw)
To: linux-tip-commits; +Cc: Peter Zijlstra (Intel), Kees Cook, x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: dbf3638d81bf009568de02bde9dc5fda9769e672
Gitweb: https://git.kernel.org/tip/dbf3638d81bf009568de02bde9dc5fda9769e672
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:06 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 26 Feb 2025 11:41:54 +01:00
x86/traps: Decode 0xEA #UD
FineIBT will start using 0xEA as #UD
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.166774696@infradead.org
---
arch/x86/include/asm/bug.h | 1 +
arch/x86/kernel/traps.c | 20 +++++++++++++++++---
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h
index 1a5e4b3..bc8a2ca 100644
--- a/arch/x86/include/asm/bug.h
+++ b/arch/x86/include/asm/bug.h
@@ -25,6 +25,7 @@
#define BUG_UD2 0xfffe
#define BUG_UD1 0xfffd
#define BUG_UD1_UBSAN 0xfffc
+#define BUG_EA 0xffea
#ifdef CONFIG_GENERIC_BUG
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 05b86c0..a02a51b 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -96,6 +96,7 @@ __always_inline int is_valid_bugaddr(unsigned long addr)
* Check for UD1 or UD2, accounting for Address Size Override Prefixes.
* If it's a UD1, further decode to determine its use:
*
+ * FineIBT: ea (bad)
* UBSan{0}: 67 0f b9 00 ud1 (%eax),%eax
* UBSan{10}: 67 0f b9 40 10 ud1 0x10(%eax),%eax
* static_call: 0f b9 cc ud1 %esp,%ecx
@@ -113,6 +114,10 @@ __always_inline int decode_bug(unsigned long addr, s32 *imm, int *len)
v = *(u8 *)(addr++);
if (v == INSN_ASOP)
v = *(u8 *)(addr++);
+ if (v == 0xea) {
+ *len = addr - start;
+ return BUG_EA;
+ }
if (v != OPCODE_ESCAPE)
return BUG_NONE;
@@ -309,10 +314,16 @@ static noinstr bool handle_bug(struct pt_regs *regs)
switch (ud_type) {
case BUG_UD2:
- if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN ||
- handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) {
- regs->ip += ud_len;
+ if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN) {
+ handled = true;
+ break;
+ }
+ fallthrough;
+
+ case BUG_EA:
+ if (handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) {
handled = true;
+ break;
}
break;
@@ -328,6 +339,9 @@ static noinstr bool handle_bug(struct pt_regs *regs)
break;
}
+ if (handled)
+ regs->ip += ud_len;
+
if (regs->flags & X86_EFLAGS_IF)
raw_local_irq_disable();
instrumentation_end();
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/cfi: Add warn option
2025-02-24 12:37 ` [PATCH v4 01/10] x86/cfi: Add warn option Peter Zijlstra
2025-02-24 18:57 ` Kees Cook
@ 2025-02-26 10:54 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/cfi: Add 'cfi=warn' boot option tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 10:54 UTC (permalink / raw)
To: linux-tip-commits; +Cc: Peter Zijlstra (Intel), Kees Cook, x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: f003da5d29a179bd1beb4ef87ac93a3ca6ddf734
Gitweb: https://git.kernel.org/tip/f003da5d29a179bd1beb4ef87ac93a3ca6ddf734
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:04 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 26 Feb 2025 11:41:53 +01:00
x86/cfi: Add warn option
Rebuilding with CFI_PERMISSIVE toggled is such a pain, esp. since
clang is so slow.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124159.924496481@infradead.org
---
arch/x86/kernel/alternative.c | 3 +++
include/linux/cfi.h | 2 ++
kernel/cfi.c | 4 +++-
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 247ee5f..1142ebd 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1022,6 +1022,9 @@ static __init int cfi_parse_cmdline(char *str)
cfi_mode = CFI_FINEIBT;
} else if (!strcmp(str, "norand")) {
cfi_rand = false;
+ } else if (!strcmp(str, "warn")) {
+ pr_alert("CFI mismatch non-fatal!\n");
+ cfi_warn = true;
} else {
pr_err("Ignoring unknown cfi option (%s).", str);
}
diff --git a/include/linux/cfi.h b/include/linux/cfi.h
index f0df518..1db17ec 100644
--- a/include/linux/cfi.h
+++ b/include/linux/cfi.h
@@ -11,6 +11,8 @@
#include <linux/module.h>
#include <asm/cfi.h>
+extern bool cfi_warn;
+
#ifndef cfi_get_offset
static inline int cfi_get_offset(void)
{
diff --git a/kernel/cfi.c b/kernel/cfi.c
index 08caad7..19be796 100644
--- a/kernel/cfi.c
+++ b/kernel/cfi.c
@@ -7,6 +7,8 @@
#include <linux/cfi.h>
+bool cfi_warn __ro_after_init = IS_ENABLED(CONFIG_CFI_PERMISSIVE);
+
enum bug_trap_type report_cfi_failure(struct pt_regs *regs, unsigned long addr,
unsigned long *target, u32 type)
{
@@ -17,7 +19,7 @@ enum bug_trap_type report_cfi_failure(struct pt_regs *regs, unsigned long addr,
pr_err("CFI failure at %pS (no target information)\n",
(void *)addr);
- if (IS_ENABLED(CONFIG_CFI_PERMISSIVE)) {
+ if (cfi_warn) {
__warn(NULL, 0, (void *)addr, 0, regs, NULL);
return BUG_TRAP_TYPE_WARN;
}
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/ibt: Optimize the fineibt-bhi arity 1 case
2025-02-24 12:37 ` [PATCH v4 10/10] x86/ibt: Optimize fineibt-bhi arity 1 case Peter Zijlstra
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
@ 2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:54 ` tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 12:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Scott Constable, Peter Zijlstra (Intel), Ingo Molnar, Kees Cook,
x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: 496ce4741ccbc91838df4bf9e137eda99c61f500
Gitweb: https://git.kernel.org/tip/496ce4741ccbc91838df4bf9e137eda99c61f500
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:13 +01:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Wed, 26 Feb 2025 12:30:52 +01:00
x86/ibt: Optimize the fineibt-bhi arity 1 case
Saves a CALL to an out-of-line thunk for the common case of 1
argument.
Suggested-by: Scott Constable <scott.d.constable@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.927885784@infradead.org
---
arch/x86/include/asm/ibt.h | 4 ++-
arch/x86/kernel/alternative.c | 59 ++++++++++++++++++++++++++++------
2 files changed, 54 insertions(+), 9 deletions(-)
diff --git a/arch/x86/include/asm/ibt.h b/arch/x86/include/asm/ibt.h
index f0ca5c0..9423a29 100644
--- a/arch/x86/include/asm/ibt.h
+++ b/arch/x86/include/asm/ibt.h
@@ -70,6 +70,10 @@ static inline bool __is_endbr(u32 val)
if (val == gen_endbr_poison())
return true;
+ /* See cfi_fineibt_bhi_preamble() */
+ if (IS_ENABLED(CONFIG_FINEIBT_BHI) && val == 0x001f0ff5)
+ return true;
+
val &= ~0x01000000U; /* ENDBR32 -> ENDBR64 */
return val == gen_endbr();
}
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index b8d65d5..32e4b80 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1311,6 +1311,53 @@ static int cfi_rand_preamble(s32 *start, s32 *end)
return 0;
}
+static void cfi_fineibt_bhi_preamble(void *addr, int arity)
+{
+ if (!arity)
+ return;
+
+ if (!cfi_warn && arity == 1) {
+ /*
+ * Crazy scheme to allow arity-1 inline:
+ *
+ * __cfi_foo:
+ * 0: f3 0f 1e fa endbr64
+ * 4: 41 81 <ea> 78 56 34 12 sub 0x12345678, %r10d
+ * b: 49 0f 45 fa cmovne %r10, %rdi
+ * f: 75 f5 jne __cfi_foo+6
+ * 11: 0f 1f 00 nopl (%rax)
+ *
+ * Code that direct calls to foo()+0, decodes the tail end as:
+ *
+ * foo:
+ * 0: f5 cmc
+ * 1: 0f 1f 00 nopl (%rax)
+ *
+ * which clobbers CF, but does not affect anything ABI
+ * wise.
+ *
+ * Notably, this scheme is incompatible with permissive CFI
+ * because the CMOVcc is unconditional and RDI will have been
+ * clobbered.
+ */
+ const u8 magic[9] = {
+ 0x49, 0x0f, 0x45, 0xfa,
+ 0x75, 0xf5,
+ BYTES_NOP3,
+ };
+
+ text_poke_early(addr + fineibt_preamble_bhi, magic, 9);
+
+ return;
+ }
+
+ text_poke_early(addr + fineibt_preamble_bhi,
+ text_gen_insn(CALL_INSN_OPCODE,
+ addr + fineibt_preamble_bhi,
+ __bhi_args[arity]),
+ CALL_INSN_SIZE);
+}
+
static int cfi_rewrite_preamble(s32 *start, s32 *end)
{
s32 *s;
@@ -1341,14 +1388,8 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
"kCFI preamble has wrong register at: %pS %*ph\n",
addr, 5, addr);
- if (!cfi_bhi || !arity)
- continue;
-
- text_poke_early(addr + fineibt_preamble_bhi,
- text_gen_insn(CALL_INSN_OPCODE,
- addr + fineibt_preamble_bhi,
- __bhi_args[arity]),
- CALL_INSN_SIZE);
+ if (cfi_bhi)
+ cfi_fineibt_bhi_preamble(addr, arity);
}
return 0;
@@ -1361,7 +1402,7 @@ static void cfi_rewrite_endbr(s32 *start, s32 *end)
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
- if (!is_endbr(addr + 16))
+ if (!exact_endbr(addr + 16))
continue;
poison_endbr(addr + 16);
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/ibt: Implement FineIBT-BHI mitigation
2025-02-24 12:37 ` [PATCH v4 09/10] x86/ibt: Implement FineIBT-BHI mitigation Peter Zijlstra
2025-02-25 9:12 ` Peter Zijlstra
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
@ 2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:54 ` tip-bot2 for Peter Zijlstra
3 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 12:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Scott Constable, Peter Zijlstra (Intel), Ingo Molnar, Kees Cook,
x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: d8122c428076ee5281baa045edaa502b316e4157
Gitweb: https://git.kernel.org/tip/d8122c428076ee5281baa045edaa502b316e4157
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:12 +01:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Wed, 26 Feb 2025 12:28:57 +01:00
x86/ibt: Implement FineIBT-BHI mitigation
While WAIT_FOR_ENDBR is specified to be a full speculation stop; it
has been shown that some implementations are 'leaky' to such an extend
that speculation can escape even the FineIBT preamble.
To deal with this, add additional hardening to the FineIBT preamble.
Notably, using a new LLVM feature:
https://github.com/llvm/llvm-project/commit/e223485c9b38a5579991b8cebb6a200153eee245
which encodes the number of arguments in the kCFI preamble's register.
Using this register<->arity mapping, have the FineIBT preamble CALL
into a stub clobbering the relevant argument registers in the
speculative case.
Scott sayeth thusly:
Microarchitectural attacks such as Branch History Injection (BHI) and
Intra-mode Branch Target Injection (IMBTI) [1] can cause an indirect
call to mispredict to an adversary-influenced target within the same
hardware domain (e.g., within the kernel). Instructions at the
mispredicted target may execute speculatively and potentially expose
kernel data (e.g., to a user-mode adversary) through a
microarchitectural covert channel such as CPU cache state.
CET-IBT [2] is a coarse-grained control-flow integrity (CFI) ISA
extension that enforces that each indirect call (or indirect jump)
must land on an ENDBR (end branch) instruction, even speculatively*.
FineIBT is a software technique that refines CET-IBT by associating
each function type with a 32-bit hash and enforcing (at the callee)
that the hash of the caller's function pointer type matches the hash
of the callee's function type. However, recent research [3] has
demonstrated that the conditional branch that enforces FineIBT's hash
check can be coerced to mispredict, potentially allowing an adversary
to speculatively bypass the hash check:
__cfi_foo:
ENDBR64
SUB R10d, 0x01234567
JZ foo # Even if the hash check fails and ZF=0, this branch could still mispredict as taken
UD2
foo:
...
The techniques demonstrated in [3] require the attacker to be able to
control the contents of at least one live register at the mispredicted
target. Therefore, this patch set introduces a sequence of CMOV
instructions at each indirect-callable target that poisons every live
register with data that the attacker cannot control whenever the
FineIBT hash check fails, thus mitigating any potential attack.
The security provided by this scheme has been discussed in detail on
an earlier thread [4].
[1] https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/branch-history-injection.html
[2] Intel Software Developer's Manual, Volume 1, Chapter 18
[3] https://www.vusec.net/projects/native-bhi/
[4] https://lore.kernel.org/lkml/20240927194925.707462984@infradead.org/
*There are some caveats for certain processors, see [1] for more info
Suggested-by: Scott Constable <scott.d.constable@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.820402212@infradead.org
---
Makefile | 3 +-
arch/x86/Kconfig | 8 ++-
arch/x86/include/asm/cfi.h | 6 ++-
arch/x86/kernel/alternative.c | 107 +++++++++++++++++++++++++++++----
arch/x86/net/bpf_jit_comp.c | 29 ++++++---
5 files changed, 134 insertions(+), 19 deletions(-)
diff --git a/Makefile b/Makefile
index 96407c1..f19431f 100644
--- a/Makefile
+++ b/Makefile
@@ -1014,6 +1014,9 @@ CC_FLAGS_CFI := -fsanitize=kcfi
ifdef CONFIG_CFI_ICALL_NORMALIZE_INTEGERS
CC_FLAGS_CFI += -fsanitize-cfi-icall-experimental-normalize-integers
endif
+ifdef CONFIG_FINEIBT_BHI
+ CC_FLAGS_CFI += -fsanitize-kcfi-arity
+endif
ifdef CONFIG_RUST
# Always pass -Zsanitizer-cfi-normalize-integers as CONFIG_RUST selects
# CONFIG_CFI_ICALL_NORMALIZE_INTEGERS.
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index c4175f4..5c27726 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2473,6 +2473,10 @@ config CC_HAS_RETURN_THUNK
config CC_HAS_ENTRY_PADDING
def_bool $(cc-option,-fpatchable-function-entry=16,16)
+config CC_HAS_KCFI_ARITY
+ def_bool $(cc-option,-fsanitize=kcfi -fsanitize-kcfi-arity)
+ depends on CC_IS_CLANG && !RUST
+
config FUNCTION_PADDING_CFI
int
default 59 if FUNCTION_ALIGNMENT_64B
@@ -2498,6 +2502,10 @@ config FINEIBT
depends on X86_KERNEL_IBT && CFI_CLANG && MITIGATION_RETPOLINE
select CALL_PADDING
+config FINEIBT_BHI
+ def_bool y
+ depends on FINEIBT && CC_HAS_KCFI_ARITY
+
config HAVE_CALL_THUNKS
def_bool y
depends on CC_HAS_ENTRY_PADDING && MITIGATION_RETHUNK && OBJTOOL
diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h
index 7c15c4b..2f6a01f 100644
--- a/arch/x86/include/asm/cfi.h
+++ b/arch/x86/include/asm/cfi.h
@@ -100,6 +100,7 @@ enum cfi_mode {
};
extern enum cfi_mode cfi_mode;
+extern bool cfi_bhi;
typedef u8 bhi_thunk[32];
extern bhi_thunk __bhi_args[];
@@ -129,6 +130,7 @@ static inline int cfi_get_offset(void)
#define cfi_get_offset cfi_get_offset
extern u32 cfi_get_func_hash(void *func);
+extern int cfi_get_func_arity(void *func);
#ifdef CONFIG_FINEIBT
extern bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type);
@@ -152,6 +154,10 @@ static inline u32 cfi_get_func_hash(void *func)
{
return 0;
}
+static inline int cfi_get_func_arity(void *func)
+{
+ return 0;
+}
#endif /* CONFIG_CFI_CLANG */
#if HAS_KERNEL_IBT == 1
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index c698c9e..b8d65d5 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -936,6 +936,7 @@ void __init_or_module apply_seal_endbr(s32 *start, s32 *end) { }
#endif
enum cfi_mode cfi_mode __ro_after_init = __CFI_DEFAULT;
+bool cfi_bhi __ro_after_init = false;
#ifdef CONFIG_CFI_CLANG
struct bpf_insn;
@@ -996,6 +997,21 @@ u32 cfi_get_func_hash(void *func)
return hash;
}
+
+int cfi_get_func_arity(void *func)
+{
+ bhi_thunk *target;
+ s32 disp;
+
+ if (cfi_mode != CFI_FINEIBT && !cfi_bhi)
+ return 0;
+
+ if (get_kernel_nofault(disp, func - 4))
+ return 0;
+
+ target = func + disp;
+ return target - __bhi_args;
+}
#endif
#ifdef CONFIG_FINEIBT
@@ -1053,6 +1069,12 @@ static __init int cfi_parse_cmdline(char *str)
} else {
pr_err("Ignoring paranoid; depends on fineibt.\n");
}
+ } else if (!strcmp(str, "bhi")) {
+ if (cfi_mode == CFI_FINEIBT) {
+ cfi_bhi = true;
+ } else {
+ pr_err("Ignoring bhi; depends on fineibt.\n");
+ }
} else {
pr_err("Ignoring unknown cfi option (%s).", str);
}
@@ -1105,6 +1127,7 @@ asm( ".pushsection .rodata \n"
"fineibt_preamble_start: \n"
" endbr64 \n"
" subl $0x12345678, %r10d \n"
+ "fineibt_preamble_bhi: \n"
" jne fineibt_preamble_start+6 \n"
ASM_NOP3
"fineibt_preamble_end: \n"
@@ -1112,9 +1135,11 @@ asm( ".pushsection .rodata \n"
);
extern u8 fineibt_preamble_start[];
+extern u8 fineibt_preamble_bhi[];
extern u8 fineibt_preamble_end[];
#define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start)
+#define fineibt_preamble_bhi (fineibt_preamble_bhi - fineibt_preamble_start)
#define fineibt_preamble_ud 6
#define fineibt_preamble_hash 7
@@ -1187,13 +1212,16 @@ extern u8 fineibt_paranoid_end[];
#define fineibt_paranoid_ind (fineibt_paranoid_ind - fineibt_paranoid_start)
#define fineibt_paranoid_ud 0xd
-static u32 decode_preamble_hash(void *addr)
+static u32 decode_preamble_hash(void *addr, int *reg)
{
u8 *p = addr;
- /* b8 78 56 34 12 mov $0x12345678,%eax */
- if (p[0] == 0xb8)
+ /* b8+reg 78 56 34 12 movl $0x12345678,\reg */
+ if (p[0] >= 0xb8 && p[0] < 0xc0) {
+ if (reg)
+ *reg = p[0] - 0xb8;
return *(u32 *)(addr + 1);
+ }
return 0; /* invalid hash value */
}
@@ -1202,11 +1230,11 @@ static u32 decode_caller_hash(void *addr)
{
u8 *p = addr;
- /* 41 ba 78 56 34 12 mov $0x12345678,%r10d */
+ /* 41 ba 88 a9 cb ed mov $(-0x12345678),%r10d */
if (p[0] == 0x41 && p[1] == 0xba)
return -*(u32 *)(addr + 2);
- /* e8 0c 78 56 34 12 jmp.d8 +12 */
+ /* e8 0c 88 a9 cb ed jmp.d8 +12 */
if (p[0] == JMP8_INSN_OPCODE && p[1] == fineibt_caller_jmp)
return -*(u32 *)(addr + 2);
@@ -1271,7 +1299,7 @@ static int cfi_rand_preamble(s32 *start, s32 *end)
void *addr = (void *)s + *s;
u32 hash;
- hash = decode_preamble_hash(addr);
+ hash = decode_preamble_hash(addr, NULL);
if (WARN(!hash, "no CFI hash found at: %pS %px %*ph\n",
addr, addr, 5, addr))
return -EINVAL;
@@ -1289,6 +1317,7 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ int arity;
u32 hash;
/*
@@ -1299,7 +1328,7 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
if (!is_endbr(addr + 16))
continue;
- hash = decode_preamble_hash(addr);
+ hash = decode_preamble_hash(addr, &arity);
if (WARN(!hash, "no CFI hash found at: %pS %px %*ph\n",
addr, addr, 5, addr))
return -EINVAL;
@@ -1307,6 +1336,19 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
text_poke_early(addr, fineibt_preamble_start, fineibt_preamble_size);
WARN_ON(*(u32 *)(addr + fineibt_preamble_hash) != 0x12345678);
text_poke_early(addr + fineibt_preamble_hash, &hash, 4);
+
+ WARN_ONCE(!IS_ENABLED(CONFIG_FINEIBT_BHI) && arity,
+ "kCFI preamble has wrong register at: %pS %*ph\n",
+ addr, 5, addr);
+
+ if (!cfi_bhi || !arity)
+ continue;
+
+ text_poke_early(addr + fineibt_preamble_bhi,
+ text_gen_insn(CALL_INSN_OPCODE,
+ addr + fineibt_preamble_bhi,
+ __bhi_args[arity]),
+ CALL_INSN_SIZE);
}
return 0;
@@ -1474,8 +1516,9 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
cfi_rewrite_endbr(start_cfi, end_cfi);
if (builtin) {
- pr_info("Using %sFineIBT CFI\n",
- cfi_paranoid ? "paranoid " : "");
+ pr_info("Using %sFineIBT%s CFI\n",
+ cfi_paranoid ? "paranoid " : "",
+ cfi_bhi ? "+BHI" : "");
}
return;
@@ -1526,7 +1569,7 @@ static void poison_cfi(void *addr)
/*
* kCFI prefix should start with a valid hash.
*/
- if (!decode_preamble_hash(addr))
+ if (!decode_preamble_hash(addr, NULL))
break;
/*
@@ -1575,6 +1618,47 @@ Efault:
}
/*
+ * regs->ip points to one of the UD2 in __bhi_args[].
+ */
+static bool decode_fineibt_bhi(struct pt_regs *regs, unsigned long *target, u32 *type)
+{
+ unsigned long addr;
+ u32 hash;
+
+ if (!cfi_bhi)
+ return false;
+
+ if (regs->ip < (unsigned long)__bhi_args ||
+ regs->ip >= (unsigned long)__bhi_args_end)
+ return false;
+
+ /*
+ * Fetch the return address from the stack, this points to the
+ * FineIBT preamble. Since the CALL instruction is in the 5 last
+ * bytes of the preamble, the return address is in fact the target
+ * address.
+ */
+ __get_kernel_nofault(&addr, regs->sp, unsigned long, Efault);
+ *target = addr;
+
+ addr -= fineibt_preamble_size;
+ if (!exact_endbr((void *)addr))
+ return false;
+
+ __get_kernel_nofault(&hash, addr + fineibt_preamble_hash, u32, Efault);
+ *type = (u32)regs->r10 + hash;
+
+ /*
+ * The UD2 sites are constructed with a RET immediately following,
+ * as such the non-fatal case can use the regular fixup.
+ */
+ return true;
+
+Efault:
+ return false;
+}
+
+/*
* regs->ip points to a LOCK Jcc.d8 instruction from the fineibt_paranoid_start[]
* sequence.
*/
@@ -1605,6 +1689,9 @@ bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
if (decode_fineibt_paranoid(regs, target, type))
return true;
+ if (decode_fineibt_bhi(regs, target, type))
+ return true;
+
return decode_fineibt_preamble(regs, target, type);
}
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index ce033e6..72776dc 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -410,15 +410,20 @@ static void emit_nops(u8 **pprog, int len)
* Emit the various CFI preambles, see asm/cfi.h and the comments about FineIBT
* in arch/x86/kernel/alternative.c
*/
+static int emit_call(u8 **prog, void *func, void *ip);
-static void emit_fineibt(u8 **pprog, u32 hash)
+static void emit_fineibt(u8 **pprog, u8 *ip, u32 hash, int arity)
{
u8 *prog = *pprog;
EMIT_ENDBR();
EMIT3_off32(0x41, 0x81, 0xea, hash); /* subl $hash, %r10d */
- EMIT2(0x75, 0xf9); /* jne.d8 .-7 */
- EMIT3(0x0f, 0x1f, 0x00); /* nop3 */
+ if (cfi_bhi) {
+ emit_call(&prog, __bhi_args[arity], ip + 11);
+ } else {
+ EMIT2(0x75, 0xf9); /* jne.d8 .-7 */
+ EMIT3(0x0f, 0x1f, 0x00); /* nop3 */
+ }
EMIT_ENDBR_POISON();
*pprog = prog;
@@ -447,13 +452,13 @@ static void emit_kcfi(u8 **pprog, u32 hash)
*pprog = prog;
}
-static void emit_cfi(u8 **pprog, u32 hash)
+static void emit_cfi(u8 **pprog, u8 *ip, u32 hash, int arity)
{
u8 *prog = *pprog;
switch (cfi_mode) {
case CFI_FINEIBT:
- emit_fineibt(&prog, hash);
+ emit_fineibt(&prog, ip, hash, arity);
break;
case CFI_KCFI:
@@ -504,13 +509,17 @@ static void emit_prologue_tail_call(u8 **pprog, bool is_subprog)
* bpf_tail_call helper will skip the first X86_TAIL_CALL_OFFSET bytes
* while jumping to another program
*/
-static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf,
+static void emit_prologue(u8 **pprog, u8 *ip, u32 stack_depth, bool ebpf_from_cbpf,
bool tail_call_reachable, bool is_subprog,
bool is_exception_cb)
{
u8 *prog = *pprog;
- emit_cfi(&prog, is_subprog ? cfi_bpf_subprog_hash : cfi_bpf_hash);
+ if (is_subprog) {
+ emit_cfi(&prog, ip, cfi_bpf_subprog_hash, 5);
+ } else {
+ emit_cfi(&prog, ip, cfi_bpf_hash, 1);
+ }
/* BPF trampoline can be made to work without these nops,
* but let's waste 5 bytes for now and optimize later
*/
@@ -1479,7 +1488,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
detect_reg_usage(insn, insn_cnt, callee_regs_used);
- emit_prologue(&prog, stack_depth,
+ emit_prologue(&prog, image, stack_depth,
bpf_prog_was_classic(bpf_prog), tail_call_reachable,
bpf_is_subprog(bpf_prog), bpf_prog->aux->exception_cb);
/* Exception callback will clobber callee regs for its own use, and
@@ -3046,7 +3055,9 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
/*
* Indirect call for bpf_struct_ops
*/
- emit_cfi(&prog, cfi_get_func_hash(func_addr));
+ emit_cfi(&prog, image,
+ cfi_get_func_hash(func_addr),
+ cfi_get_func_arity(func_addr));
} else {
/*
* Direct-call fentry stub, as such it needs accounting for the
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/bhi: Add BHI stubs
2025-02-24 12:37 ` [PATCH v4 08/10] x86: BHI stubs Peter Zijlstra
2025-02-24 19:01 ` Kees Cook
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
@ 2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:54 ` tip-bot2 for Peter Zijlstra
3 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 12:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Peter Zijlstra (Intel), Ingo Molnar, Kees Cook, x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: a18e6715ff4e6e71c2b5dc8ec78f2ddc3fe4b0a8
Gitweb: https://git.kernel.org/tip/a18e6715ff4e6e71c2b5dc8ec78f2ddc3fe4b0a8
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:11 +01:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Wed, 26 Feb 2025 12:28:20 +01:00
x86/bhi: Add BHI stubs
Add an array of code thunks, to be called from the FineIBT preamble,
clobbering the first 'n' argument registers for speculative execution.
Notably the 0th entry will clobber no argument registers and will never
be used, it exists so the array can be naturally indexed, while the 7th
entry will clobber all the 6 argument registers and also RSP in order to
mess up stack based arguments.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.717378681@infradead.org
---
arch/x86/include/asm/cfi.h | 4 +-
arch/x86/lib/Makefile | 3 +-
arch/x86/lib/bhi.S | 146 ++++++++++++++++++++++++++++++++++++-
3 files changed, 152 insertions(+), 1 deletion(-)
create mode 100644 arch/x86/lib/bhi.S
diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h
index 7dd5ab2..7c15c4b 100644
--- a/arch/x86/include/asm/cfi.h
+++ b/arch/x86/include/asm/cfi.h
@@ -101,6 +101,10 @@ enum cfi_mode {
extern enum cfi_mode cfi_mode;
+typedef u8 bhi_thunk[32];
+extern bhi_thunk __bhi_args[];
+extern bhi_thunk __bhi_args_end[];
+
struct pt_regs;
#ifdef CONFIG_CFI_CLANG
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 8a59c61..f453507 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -66,5 +66,6 @@ endif
lib-y += clear_page_64.o copy_page_64.o
lib-y += memmove_64.o memset_64.o
lib-y += copy_user_64.o copy_user_uncached_64.o
- lib-y += cmpxchg16b_emu.o
+ lib-y += cmpxchg16b_emu.o
+ lib-y += bhi.o
endif
diff --git a/arch/x86/lib/bhi.S b/arch/x86/lib/bhi.S
new file mode 100644
index 0000000..421e307
--- /dev/null
+++ b/arch/x86/lib/bhi.S
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/linkage.h>
+#include <asm/unwind_hints.h>
+#include <asm/nospec-branch.h>
+
+/*
+ * Notably, the FineIBT preamble calling these will have ZF set and r10 zero.
+ *
+ * The very last element is in fact larger than 32 bytes, but since its the
+ * last element, this does not matter,
+ *
+ * There are 2 #UD sites, located between 0,1-2,3 and 4,5-6,7 such that they
+ * can be reached using Jcc.d8, these elements (1 and 5) have sufficiently
+ * big alignment holes for this to not stagger the array.
+ */
+
+.pushsection .noinstr.text, "ax"
+
+ .align 32
+SYM_CODE_START(__bhi_args)
+
+#ifdef CONFIG_FINEIBT_BHI
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_0, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_1, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ cmovne %r10, %rdi
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 8
+ ANNOTATE_REACHABLE
+.Lud_1: ud2
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_2, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_3, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_4, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_5, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ cmovne %r10, %r8
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 8
+ ANNOTATE_REACHABLE
+.Lud_2: ud2
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_6, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ cmovne %r10, %r8
+ cmovne %r10, %r9
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_7, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ cmovne %r10, %r8
+ cmovne %r10, %r9
+ cmovne %r10, %rsp
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+#endif /* CONFIG_FINEIBT_BHI */
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_end, SYM_L_GLOBAL)
+ ANNOTATE_NOENDBR
+SYM_CODE_END(__bhi_args)
+
+.popsection
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/traps: Decode LOCK Jcc.d8 as #UD
2025-02-24 12:37 ` [PATCH v4 06/10] x86/traps: Decode LOCK Jcc.d8 #UD Peter Zijlstra
2025-02-24 21:46 ` David Laight
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
@ 2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 12:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Peter Zijlstra (Intel), Ingo Molnar, Kees Cook, x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: 029f718fedd72872f7475604fe71b2a841108834
Gitweb: https://git.kernel.org/tip/029f718fedd72872f7475604fe71b2a841108834
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:09 +01:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Wed, 26 Feb 2025 12:24:17 +01:00
x86/traps: Decode LOCK Jcc.d8 as #UD
Because overlapping code sequences are all the rage.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.486463917@infradead.org
---
arch/x86/include/asm/bug.h | 2 ++
arch/x86/kernel/traps.c | 26 +++++++++++++++++++++++---
2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h
index bc8a2ca..f0e9acf 100644
--- a/arch/x86/include/asm/bug.h
+++ b/arch/x86/include/asm/bug.h
@@ -17,6 +17,7 @@
* In clang we have UD1s reporting UBSAN failures on X86, 64 and 32bit.
*/
#define INSN_ASOP 0x67
+#define INSN_LOCK 0xf0
#define OPCODE_ESCAPE 0x0f
#define SECOND_BYTE_OPCODE_UD1 0xb9
#define SECOND_BYTE_OPCODE_UD2 0x0b
@@ -26,6 +27,7 @@
#define BUG_UD1 0xfffd
#define BUG_UD1_UBSAN 0xfffc
#define BUG_EA 0xffea
+#define BUG_LOCK 0xfff0
#ifdef CONFIG_GENERIC_BUG
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index c169f3b..f4263cb 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -97,6 +97,7 @@ __always_inline int is_valid_bugaddr(unsigned long addr)
* If it's a UD1, further decode to determine its use:
*
* FineIBT: ea (bad)
+ * FineIBT: f0 75 f9 lock jne . - 6
* UBSan{0}: 67 0f b9 00 ud1 (%eax),%eax
* UBSan{10}: 67 0f b9 40 10 ud1 0x10(%eax),%eax
* static_call: 0f b9 cc ud1 %esp,%ecx
@@ -106,6 +107,7 @@ __always_inline int is_valid_bugaddr(unsigned long addr)
__always_inline int decode_bug(unsigned long addr, s32 *imm, int *len)
{
unsigned long start = addr;
+ bool lock = false;
u8 v;
if (addr < TASK_SIZE_MAX)
@@ -114,12 +116,29 @@ __always_inline int decode_bug(unsigned long addr, s32 *imm, int *len)
v = *(u8 *)(addr++);
if (v == INSN_ASOP)
v = *(u8 *)(addr++);
- if (v == 0xea) {
+
+ if (v == INSN_LOCK) {
+ lock = true;
+ v = *(u8 *)(addr++);
+ }
+
+ switch (v) {
+ case 0x70 ... 0x7f: /* Jcc.d8 */
+ addr += 1; /* d8 */
+ *len = addr - start;
+ WARN_ON_ONCE(!lock);
+ return BUG_LOCK;
+
+ case 0xea:
*len = addr - start;
return BUG_EA;
- }
- if (v != OPCODE_ESCAPE)
+
+ case OPCODE_ESCAPE:
+ break;
+
+ default:
return BUG_NONE;
+ }
v = *(u8 *)(addr++);
if (v == SECOND_BYTE_OPCODE_UD2) {
@@ -322,6 +341,7 @@ static noinstr bool handle_bug(struct pt_regs *regs)
fallthrough;
case BUG_EA:
+ case BUG_LOCK:
if (handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) {
handled = true;
break;
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/ibt: Add paranoid FineIBT mode
2025-02-24 12:37 ` [PATCH v4 07/10] x86/ibt: Add paranoid FineIBT mode Peter Zijlstra
2025-02-24 19:00 ` Kees Cook
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
@ 2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 12:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Scott Constable, Jennifer Miller, Peter Zijlstra (Intel),
Ingo Molnar, Kees Cook, x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: 97e59672a9d2aec0c27f6cd6a6b0edfdd6e5a85c
Gitweb: https://git.kernel.org/tip/97e59672a9d2aec0c27f6cd6a6b0edfdd6e5a85c
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Wed, 26 Feb 2025 12:25:17 +01:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Wed, 26 Feb 2025 12:27:45 +01:00
x86/ibt: Add paranoid FineIBT mode
Due to concerns about circumvention attacks against FineIBT on 'naked'
ENDBR, add an additional caller side hash check to FineIBT. This
should make it impossible to pivot over such a 'naked' ENDBR
instruction at the cost of an additional load.
The specific pivot reported was against the SYSCALL entry site and
FRED will have all those holes fixed up.
https://lore.kernel.org/linux-hardening/Z60NwR4w%2F28Z7XUa@ubun/
This specific fineibt_paranoid_start[] sequence was concocted by
Scott.
Suggested-by: Scott Constable <scott.d.constable@intel.com>
Reported-by: Jennifer Miller <jmill@asu.edu>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.598033084@infradead.org
---
arch/x86/kernel/alternative.c | 144 +++++++++++++++++++++++++++++++--
1 file changed, 138 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index a2e8ee8..c698c9e 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -741,6 +741,11 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
op2 = insn.opcode.bytes[1];
switch (op1) {
+ case 0x70 ... 0x7f: /* Jcc.d8 */
+ /* See cfi_paranoid. */
+ WARN_ON_ONCE(cfi_mode != CFI_FINEIBT);
+ continue;
+
case CALL_INSN_OPCODE:
case JMP32_INSN_OPCODE:
break;
@@ -998,6 +1003,8 @@ u32 cfi_get_func_hash(void *func)
static bool cfi_rand __ro_after_init = true;
static u32 cfi_seed __ro_after_init;
+static bool cfi_paranoid __ro_after_init = false;
+
/*
* Re-hash the CFI hash with a boot-time seed while making sure the result is
* not a valid ENDBR instruction.
@@ -1040,6 +1047,12 @@ static __init int cfi_parse_cmdline(char *str)
} else if (!strcmp(str, "warn")) {
pr_alert("CFI mismatch non-fatal!\n");
cfi_warn = true;
+ } else if (!strcmp(str, "paranoid")) {
+ if (cfi_mode == CFI_FINEIBT) {
+ cfi_paranoid = true;
+ } else {
+ pr_err("Ignoring paranoid; depends on fineibt.\n");
+ }
} else {
pr_err("Ignoring unknown cfi option (%s).", str);
}
@@ -1128,6 +1141,52 @@ extern u8 fineibt_caller_end[];
#define fineibt_caller_jmp (fineibt_caller_size - 2)
+/*
+ * Since FineIBT does hash validation on the callee side it is prone to
+ * circumvention attacks where a 'naked' ENDBR instruction exists that
+ * is not part of the fineibt_preamble sequence.
+ *
+ * Notably the x86 entry points must be ENDBR and equally cannot be
+ * fineibt_preamble.
+ *
+ * The fineibt_paranoid caller sequence adds additional caller side
+ * hash validation. This stops such circumvention attacks dead, but at the cost
+ * of adding a load.
+ *
+ * <fineibt_paranoid_start>:
+ * 0: 41 ba 78 56 34 12 mov $0x12345678, %r10d
+ * 6: 45 3b 53 f7 cmp -0x9(%r11), %r10d
+ * a: 4d 8d 5b <f0> lea -0x10(%r11), %r11
+ * e: 75 fd jne d <fineibt_paranoid_start+0xd>
+ * 10: 41 ff d3 call *%r11
+ * 13: 90 nop
+ *
+ * Notably LEA does not modify flags and can be reordered with the CMP,
+ * avoiding a dependency. Again, using a non-taken (backwards) branch
+ * for the failure case, abusing LEA's immediate 0xf0 as LOCK prefix for the
+ * Jcc.d8, causing #UD.
+ */
+asm( ".pushsection .rodata \n"
+ "fineibt_paranoid_start: \n"
+ " movl $0x12345678, %r10d \n"
+ " cmpl -9(%r11), %r10d \n"
+ " lea -0x10(%r11), %r11 \n"
+ " jne fineibt_paranoid_start+0xd \n"
+ "fineibt_paranoid_ind: \n"
+ " call *%r11 \n"
+ " nop \n"
+ "fineibt_paranoid_end: \n"
+ ".popsection \n"
+);
+
+extern u8 fineibt_paranoid_start[];
+extern u8 fineibt_paranoid_ind[];
+extern u8 fineibt_paranoid_end[];
+
+#define fineibt_paranoid_size (fineibt_paranoid_end - fineibt_paranoid_start)
+#define fineibt_paranoid_ind (fineibt_paranoid_ind - fineibt_paranoid_start)
+#define fineibt_paranoid_ud 0xd
+
static u32 decode_preamble_hash(void *addr)
{
u8 *p = addr;
@@ -1291,18 +1350,48 @@ static int cfi_rewrite_callers(s32 *start, s32 *end)
{
s32 *s;
+ BUG_ON(fineibt_paranoid_size != 20);
+
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ struct insn insn;
+ u8 bytes[20];
u32 hash;
+ int ret;
+ u8 op;
addr -= fineibt_caller_size;
hash = decode_caller_hash(addr);
- if (hash) {
+ if (!hash)
+ continue;
+
+ if (!cfi_paranoid) {
text_poke_early(addr, fineibt_caller_start, fineibt_caller_size);
WARN_ON(*(u32 *)(addr + fineibt_caller_hash) != 0x12345678);
text_poke_early(addr + fineibt_caller_hash, &hash, 4);
+ /* rely on apply_retpolines() */
+ continue;
+ }
+
+ /* cfi_paranoid */
+ ret = insn_decode_kernel(&insn, addr + fineibt_caller_size);
+ if (WARN_ON_ONCE(ret < 0))
+ continue;
+
+ op = insn.opcode.bytes[0];
+ if (op != CALL_INSN_OPCODE && op != JMP32_INSN_OPCODE) {
+ WARN_ON_ONCE(1);
+ continue;
}
- /* rely on apply_retpolines() */
+
+ memcpy(bytes, fineibt_paranoid_start, fineibt_paranoid_size);
+ memcpy(bytes + fineibt_caller_hash, &hash, 4);
+
+ ret = emit_indirect(op, 11, bytes + fineibt_paranoid_ind);
+ if (WARN_ON_ONCE(ret != 3))
+ continue;
+
+ text_poke_early(addr, bytes, fineibt_paranoid_size);
}
return 0;
@@ -1319,8 +1408,15 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
if (cfi_mode == CFI_AUTO) {
cfi_mode = CFI_KCFI;
- if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT))
+ if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT)) {
+ /*
+ * FRED has much saner context on exception entry and
+ * is less easy to take advantage of.
+ */
+ if (!cpu_feature_enabled(X86_FEATURE_FRED))
+ cfi_paranoid = true;
cfi_mode = CFI_FINEIBT;
+ }
}
/*
@@ -1377,8 +1473,10 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
/* now that nobody targets func()+0, remove ENDBR there */
cfi_rewrite_endbr(start_cfi, end_cfi);
- if (builtin)
- pr_info("Using FineIBT CFI\n");
+ if (builtin) {
+ pr_info("Using %sFineIBT CFI\n",
+ cfi_paranoid ? "paranoid " : "");
+ }
return;
default:
@@ -1451,7 +1549,7 @@ static void poison_cfi(void *addr)
* We check the preamble by checking for the ENDBR instruction relative to the
* 0xEA instruction.
*/
-bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
+static bool decode_fineibt_preamble(struct pt_regs *regs, unsigned long *target, u32 *type)
{
unsigned long addr = regs->ip - fineibt_preamble_ud;
u32 hash;
@@ -1476,6 +1574,40 @@ Efault:
return false;
}
+/*
+ * regs->ip points to a LOCK Jcc.d8 instruction from the fineibt_paranoid_start[]
+ * sequence.
+ */
+static bool decode_fineibt_paranoid(struct pt_regs *regs, unsigned long *target, u32 *type)
+{
+ unsigned long addr = regs->ip - fineibt_paranoid_ud;
+ u32 hash;
+
+ if (!cfi_paranoid || !is_cfi_trap(addr + fineibt_caller_size - LEN_UD2))
+ return false;
+
+ __get_kernel_nofault(&hash, addr + fineibt_caller_hash, u32, Efault);
+ *target = regs->r11 + fineibt_preamble_size;
+ *type = regs->r10;
+
+ /*
+ * Since the trapping instruction is the exact, but LOCK prefixed,
+ * Jcc.d8 that got us here, the normal fixup will work.
+ */
+ return true;
+
+Efault:
+ return false;
+}
+
+bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
+{
+ if (decode_fineibt_paranoid(regs, target, type))
+ return true;
+
+ return decode_fineibt_preamble(regs, target, type);
+}
+
#else /* !CONFIG_FINEIBT: */
static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/ibt: Optimize the FineIBT instruction sequence
2025-02-24 12:37 ` [PATCH v4 05/10] x86/ibt: Optimize FineIBT sequence Peter Zijlstra
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
@ 2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
1 sibling, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 12:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Scott Constable, Peter Zijlstra (Intel), Ingo Molnar, Kees Cook,
x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: 06926c6cdb955bf24521d4e13af95b4d062d02d0
Gitweb: https://git.kernel.org/tip/06926c6cdb955bf24521d4e13af95b4d062d02d0
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:08 +01:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Wed, 26 Feb 2025 12:24:09 +01:00
x86/ibt: Optimize the FineIBT instruction sequence
Scott notes that non-taken branches are faster. Abuse overlapping code
that traps instead of explicit UD2 instructions.
And LEA does not modify flags and will have less dependencies.
Suggested-by: Scott Constable <scott.d.constable@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.371942555@infradead.org
---
arch/x86/kernel/alternative.c | 61 ++++++++++++++++++++++------------
arch/x86/net/bpf_jit_comp.c | 5 +--
2 files changed, 42 insertions(+), 24 deletions(-)
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index ea68f0e..a2e8ee8 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1057,9 +1057,9 @@ early_param("cfi", cfi_parse_cmdline);
* __cfi_\func: __cfi_\func:
* movl $0x12345678,%eax // 5 endbr64 // 4
* nop subl $0x12345678,%r10d // 7
- * nop jz 1f // 2
- * nop ud2 // 2
- * nop 1: nop // 1
+ * nop jne __cfi_\func+6 // 2
+ * nop nop3 // 3
+ * nop
* nop
* nop
* nop
@@ -1071,37 +1071,50 @@ early_param("cfi", cfi_parse_cmdline);
*
* caller: caller:
* movl $(-0x12345678),%r10d // 6 movl $0x12345678,%r10d // 6
- * addl $-15(%r11),%r10d // 4 sub $16,%r11 // 4
+ * addl $-15(%r11),%r10d // 4 lea -0x10(%r11),%r11 // 4
* je 1f // 2 nop4 // 4
* ud2 // 2
- * 1: call __x86_indirect_thunk_r11 // 5 call *%r11; nop2; // 5
+ * 1: cs call __x86_indirect_thunk_r11 // 6 call *%r11; nop3; // 6
*
*/
-asm( ".pushsection .rodata \n"
- "fineibt_preamble_start: \n"
- " endbr64 \n"
- " subl $0x12345678, %r10d \n"
- " je fineibt_preamble_end \n"
- "fineibt_preamble_ud2: \n"
- " ud2 \n"
- " nop \n"
- "fineibt_preamble_end: \n"
+/*
+ * <fineibt_preamble_start>:
+ * 0: f3 0f 1e fa endbr64
+ * 4: 41 81 <ea> 78 56 34 12 sub $0x12345678, %r10d
+ * b: 75 f9 jne 6 <fineibt_preamble_start+0x6>
+ * d: 0f 1f 00 nopl (%rax)
+ *
+ * Note that the JNE target is the 0xEA byte inside the SUB, this decodes as
+ * (bad) on x86_64 and raises #UD.
+ */
+asm( ".pushsection .rodata \n"
+ "fineibt_preamble_start: \n"
+ " endbr64 \n"
+ " subl $0x12345678, %r10d \n"
+ " jne fineibt_preamble_start+6 \n"
+ ASM_NOP3
+ "fineibt_preamble_end: \n"
".popsection\n"
);
extern u8 fineibt_preamble_start[];
-extern u8 fineibt_preamble_ud2[];
extern u8 fineibt_preamble_end[];
#define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start)
-#define fineibt_preamble_ud2 (fineibt_preamble_ud2 - fineibt_preamble_start)
+#define fineibt_preamble_ud 6
#define fineibt_preamble_hash 7
+/*
+ * <fineibt_caller_start>:
+ * 0: 41 ba 78 56 34 12 mov $0x12345678, %r10d
+ * 6: 4d 8d 5b f0 lea -0x10(%r11), %r11
+ * a: 0f 1f 40 00 nopl 0x0(%rax)
+ */
asm( ".pushsection .rodata \n"
"fineibt_caller_start: \n"
" movl $0x12345678, %r10d \n"
- " sub $16, %r11 \n"
+ " lea -0x10(%r11), %r11 \n"
ASM_NOP4
"fineibt_caller_end: \n"
".popsection \n"
@@ -1432,15 +1445,15 @@ static void poison_cfi(void *addr)
}
/*
- * regs->ip points to a UD2 instruction, return true and fill out target and
- * type when this UD2 is from a FineIBT preamble.
+ * When regs->ip points to a 0xEA byte in the FineIBT preamble,
+ * return true and fill out target and type.
*
* We check the preamble by checking for the ENDBR instruction relative to the
- * UD2 instruction.
+ * 0xEA instruction.
*/
bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
{
- unsigned long addr = regs->ip - fineibt_preamble_ud2;
+ unsigned long addr = regs->ip - fineibt_preamble_ud;
u32 hash;
if (!exact_endbr((void *)addr))
@@ -1451,6 +1464,12 @@ bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
__get_kernel_nofault(&hash, addr + fineibt_preamble_hash, u32, Efault);
*type = (u32)regs->r10 + hash;
+ /*
+ * Since regs->ip points to the middle of an instruction; it cannot
+ * continue with the normal fixup.
+ */
+ regs->ip = *target;
+
return true;
Efault:
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index f36508b..ce033e6 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -417,9 +417,8 @@ static void emit_fineibt(u8 **pprog, u32 hash)
EMIT_ENDBR();
EMIT3_off32(0x41, 0x81, 0xea, hash); /* subl $hash, %r10d */
- EMIT2(0x74, 0x07); /* jz.d8 +7 */
- EMIT2(0x0f, 0x0b); /* ud2 */
- EMIT1(0x90); /* nop */
+ EMIT2(0x75, 0xf9); /* jne.d8 .-7 */
+ EMIT3(0x0f, 0x1f, 0x00); /* nop3 */
EMIT_ENDBR_POISON();
*pprog = prog;
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/traps: Allow custom fixups in handle_bug()
2025-02-24 12:37 ` [PATCH v4 04/10] x86/traps: Allow custom fixups in handle_bug() Peter Zijlstra
2025-02-24 18:59 ` Kees Cook
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
@ 2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 12:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Peter Zijlstra (Intel), Ingo Molnar, Kees Cook, x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: e33d805a1005bf7b8a5a53559c81a8e17f0b981b
Gitweb: https://git.kernel.org/tip/e33d805a1005bf7b8a5a53559c81a8e17f0b981b
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:07 +01:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Wed, 26 Feb 2025 12:22:39 +01:00
x86/traps: Allow custom fixups in handle_bug()
The normal fixup in handle_bug() is simply continuing at the next
instruction. However upcoming patches make this the wrong thing, so
allow handlers (specifically handle_cfi_failure()) to over-ride
regs->ip.
The callchain is such that the fixup needs to be done before it is
determined if the exception is fatal, as such, revert any changes in
that case.
Additionally, have handle_cfi_failure() remember the regs->ip value it
starts with for reporting.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.275223080@infradead.org
---
arch/x86/kernel/cfi.c | 8 ++++----
arch/x86/kernel/traps.c | 16 +++++++++++++---
2 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/arch/x86/kernel/cfi.c b/arch/x86/kernel/cfi.c
index f6905be..77086cf 100644
--- a/arch/x86/kernel/cfi.c
+++ b/arch/x86/kernel/cfi.c
@@ -67,16 +67,16 @@ static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target,
*/
enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
{
- unsigned long target;
+ unsigned long target, addr = regs->ip;
u32 type;
switch (cfi_mode) {
case CFI_KCFI:
- if (!is_cfi_trap(regs->ip))
+ if (!is_cfi_trap(addr))
return BUG_TRAP_TYPE_NONE;
if (!decode_cfi_insn(regs, &target, &type))
- return report_cfi_failure_noaddr(regs, regs->ip);
+ return report_cfi_failure_noaddr(regs, addr);
break;
@@ -90,7 +90,7 @@ enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
return BUG_TRAP_TYPE_NONE;
}
- return report_cfi_failure(regs, regs->ip, &target, type);
+ return report_cfi_failure(regs, addr, &target, type);
}
/*
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index a02a51b..c169f3b 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -287,11 +287,12 @@ static inline void handle_invalid_op(struct pt_regs *regs)
static noinstr bool handle_bug(struct pt_regs *regs)
{
+ unsigned long addr = regs->ip;
bool handled = false;
int ud_type, ud_len;
s32 ud_imm;
- ud_type = decode_bug(regs->ip, &ud_imm, &ud_len);
+ ud_type = decode_bug(addr, &ud_imm, &ud_len);
if (ud_type == BUG_NONE)
return handled;
@@ -339,8 +340,17 @@ static noinstr bool handle_bug(struct pt_regs *regs)
break;
}
- if (handled)
- regs->ip += ud_len;
+ /*
+ * When continuing, and regs->ip hasn't changed, move it to the next
+ * instruction. When not continuing execution, restore the instruction
+ * pointer.
+ */
+ if (handled) {
+ if (regs->ip == addr)
+ regs->ip += ud_len;
+ } else {
+ regs->ip = addr;
+ }
if (regs->flags & X86_EFLAGS_IF)
raw_local_irq_disable();
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/traps: Decode 0xEA instructions as #UD
2025-02-24 12:37 ` [PATCH v4 03/10] x86/traps: Decode 0xEA #UD Peter Zijlstra
2025-02-24 18:58 ` Kees Cook
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
@ 2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 12:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Peter Zijlstra (Intel), Ingo Molnar, Kees Cook, x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: 2e044911be75ce3321c5b3d10205ac0b54f8cb92
Gitweb: https://git.kernel.org/tip/2e044911be75ce3321c5b3d10205ac0b54f8cb92
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:06 +01:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Wed, 26 Feb 2025 12:22:10 +01:00
x86/traps: Decode 0xEA instructions as #UD
FineIBT will start using 0xEA as #UD. Normally '0xEA' is a 'bad',
invalid instruction for the CPU.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.166774696@infradead.org
---
arch/x86/include/asm/bug.h | 1 +
arch/x86/kernel/traps.c | 20 +++++++++++++++++---
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h
index 1a5e4b3..bc8a2ca 100644
--- a/arch/x86/include/asm/bug.h
+++ b/arch/x86/include/asm/bug.h
@@ -25,6 +25,7 @@
#define BUG_UD2 0xfffe
#define BUG_UD1 0xfffd
#define BUG_UD1_UBSAN 0xfffc
+#define BUG_EA 0xffea
#ifdef CONFIG_GENERIC_BUG
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 05b86c0..a02a51b 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -96,6 +96,7 @@ __always_inline int is_valid_bugaddr(unsigned long addr)
* Check for UD1 or UD2, accounting for Address Size Override Prefixes.
* If it's a UD1, further decode to determine its use:
*
+ * FineIBT: ea (bad)
* UBSan{0}: 67 0f b9 00 ud1 (%eax),%eax
* UBSan{10}: 67 0f b9 40 10 ud1 0x10(%eax),%eax
* static_call: 0f b9 cc ud1 %esp,%ecx
@@ -113,6 +114,10 @@ __always_inline int decode_bug(unsigned long addr, s32 *imm, int *len)
v = *(u8 *)(addr++);
if (v == INSN_ASOP)
v = *(u8 *)(addr++);
+ if (v == 0xea) {
+ *len = addr - start;
+ return BUG_EA;
+ }
if (v != OPCODE_ESCAPE)
return BUG_NONE;
@@ -309,10 +314,16 @@ static noinstr bool handle_bug(struct pt_regs *regs)
switch (ud_type) {
case BUG_UD2:
- if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN ||
- handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) {
- regs->ip += ud_len;
+ if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN) {
+ handled = true;
+ break;
+ }
+ fallthrough;
+
+ case BUG_EA:
+ if (handle_cfi_failure(regs) == BUG_TRAP_TYPE_WARN) {
handled = true;
+ break;
}
break;
@@ -328,6 +339,9 @@ static noinstr bool handle_bug(struct pt_regs *regs)
break;
}
+ if (handled)
+ regs->ip += ud_len;
+
if (regs->flags & X86_EFLAGS_IF)
raw_local_irq_disable();
instrumentation_end();
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/ibt: Add exact_endbr() helper
2025-02-24 12:37 ` [PATCH v4 02/10] x86/ibt: Add exact_endbr() helper Peter Zijlstra
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
@ 2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
1 sibling, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 12:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Peter Zijlstra (Intel), Ingo Molnar, Kees Cook, x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: 500a41acb05a973cb6826ee56df082a97e210a95
Gitweb: https://git.kernel.org/tip/500a41acb05a973cb6826ee56df082a97e210a95
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:05 +01:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Wed, 26 Feb 2025 12:11:18 +01:00
x86/ibt: Add exact_endbr() helper
For when we want to exactly match ENDBR, and not everything that we
can scribble it with.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.059556588@infradead.org
---
arch/x86/kernel/alternative.c | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 1142ebd..83316ea 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -863,6 +863,21 @@ Efault:
return false;
}
+#ifdef CONFIG_FINEIBT
+
+static __noendbr bool exact_endbr(u32 *val)
+{
+ u32 endbr;
+
+ __get_kernel_nofault(&endbr, val, u32, Efault);
+ return endbr == gen_endbr();
+
+Efault:
+ return false;
+}
+
+#endif
+
static void poison_cfi(void *addr);
static void __init_or_module poison_endbr(void *addr)
@@ -1426,10 +1441,9 @@ static void poison_cfi(void *addr)
bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
{
unsigned long addr = regs->ip - fineibt_preamble_ud2;
- u32 endbr, hash;
+ u32 hash;
- __get_kernel_nofault(&endbr, addr, u32, Efault);
- if (endbr != gen_endbr())
+ if (!exact_endbr((void *)addr))
return false;
*target = addr + fineibt_preamble_size;
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/cfi: Add 'cfi=warn' boot option
2025-02-24 12:37 ` [PATCH v4 01/10] x86/cfi: Add warn option Peter Zijlstra
2025-02-24 18:57 ` Kees Cook
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
@ 2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 12:04 UTC (permalink / raw)
To: linux-tip-commits
Cc: Peter Zijlstra (Intel), Ingo Molnar, Kees Cook, x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: 9a54fb31343362f93680543e37afc14484c185d9
Gitweb: https://git.kernel.org/tip/9a54fb31343362f93680543e37afc14484c185d9
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:04 +01:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Wed, 26 Feb 2025 12:10:48 +01:00
x86/cfi: Add 'cfi=warn' boot option
Rebuilding with CONFIG_CFI_PERMISSIVE=y enabled is such a pain, esp. since
clang is so slow.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124159.924496481@infradead.org
---
arch/x86/kernel/alternative.c | 3 +++
include/linux/cfi.h | 2 ++
kernel/cfi.c | 4 +++-
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 247ee5f..1142ebd 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1022,6 +1022,9 @@ static __init int cfi_parse_cmdline(char *str)
cfi_mode = CFI_FINEIBT;
} else if (!strcmp(str, "norand")) {
cfi_rand = false;
+ } else if (!strcmp(str, "warn")) {
+ pr_alert("CFI mismatch non-fatal!\n");
+ cfi_warn = true;
} else {
pr_err("Ignoring unknown cfi option (%s).", str);
}
diff --git a/include/linux/cfi.h b/include/linux/cfi.h
index f0df518..1db17ec 100644
--- a/include/linux/cfi.h
+++ b/include/linux/cfi.h
@@ -11,6 +11,8 @@
#include <linux/module.h>
#include <asm/cfi.h>
+extern bool cfi_warn;
+
#ifndef cfi_get_offset
static inline int cfi_get_offset(void)
{
diff --git a/kernel/cfi.c b/kernel/cfi.c
index 08caad7..19be796 100644
--- a/kernel/cfi.c
+++ b/kernel/cfi.c
@@ -7,6 +7,8 @@
#include <linux/cfi.h>
+bool cfi_warn __ro_after_init = IS_ENABLED(CONFIG_CFI_PERMISSIVE);
+
enum bug_trap_type report_cfi_failure(struct pt_regs *regs, unsigned long addr,
unsigned long *target, u32 type)
{
@@ -17,7 +19,7 @@ enum bug_trap_type report_cfi_failure(struct pt_regs *regs, unsigned long addr,
pr_err("CFI failure at %pS (no target information)\n",
(void *)addr);
- if (IS_ENABLED(CONFIG_CFI_PERMISSIVE)) {
+ if (cfi_warn) {
__warn(NULL, 0, (void *)addr, 0, regs, NULL);
return BUG_TRAP_TYPE_WARN;
}
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/ibt: Optimize the fineibt-bhi arity 1 case
2025-02-24 12:37 ` [PATCH v4 10/10] x86/ibt: Optimize fineibt-bhi arity 1 case Peter Zijlstra
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/ibt: Optimize the " tip-bot2 for Peter Zijlstra
@ 2025-02-26 12:54 ` tip-bot2 for Peter Zijlstra
2 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 12:54 UTC (permalink / raw)
To: linux-tip-commits
Cc: Scott Constable, Peter Zijlstra (Intel), Ingo Molnar, Kees Cook,
x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: dfebe7362f6f461d771cdb9ac2c5172a4721f064
Gitweb: https://git.kernel.org/tip/dfebe7362f6f461d771cdb9ac2c5172a4721f064
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:13 +01:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Wed, 26 Feb 2025 13:49:11 +01:00
x86/ibt: Optimize the fineibt-bhi arity 1 case
Saves a CALL to an out-of-line thunk for the common case of 1
argument.
Suggested-by: Scott Constable <scott.d.constable@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.927885784@infradead.org
---
arch/x86/include/asm/ibt.h | 4 ++-
arch/x86/kernel/alternative.c | 59 ++++++++++++++++++++++++++++------
2 files changed, 54 insertions(+), 9 deletions(-)
diff --git a/arch/x86/include/asm/ibt.h b/arch/x86/include/asm/ibt.h
index f0ca5c0..9423a29 100644
--- a/arch/x86/include/asm/ibt.h
+++ b/arch/x86/include/asm/ibt.h
@@ -70,6 +70,10 @@ static inline bool __is_endbr(u32 val)
if (val == gen_endbr_poison())
return true;
+ /* See cfi_fineibt_bhi_preamble() */
+ if (IS_ENABLED(CONFIG_FINEIBT_BHI) && val == 0x001f0ff5)
+ return true;
+
val &= ~0x01000000U; /* ENDBR32 -> ENDBR64 */
return val == gen_endbr();
}
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index b8d65d5..32e4b80 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1311,6 +1311,53 @@ static int cfi_rand_preamble(s32 *start, s32 *end)
return 0;
}
+static void cfi_fineibt_bhi_preamble(void *addr, int arity)
+{
+ if (!arity)
+ return;
+
+ if (!cfi_warn && arity == 1) {
+ /*
+ * Crazy scheme to allow arity-1 inline:
+ *
+ * __cfi_foo:
+ * 0: f3 0f 1e fa endbr64
+ * 4: 41 81 <ea> 78 56 34 12 sub 0x12345678, %r10d
+ * b: 49 0f 45 fa cmovne %r10, %rdi
+ * f: 75 f5 jne __cfi_foo+6
+ * 11: 0f 1f 00 nopl (%rax)
+ *
+ * Code that direct calls to foo()+0, decodes the tail end as:
+ *
+ * foo:
+ * 0: f5 cmc
+ * 1: 0f 1f 00 nopl (%rax)
+ *
+ * which clobbers CF, but does not affect anything ABI
+ * wise.
+ *
+ * Notably, this scheme is incompatible with permissive CFI
+ * because the CMOVcc is unconditional and RDI will have been
+ * clobbered.
+ */
+ const u8 magic[9] = {
+ 0x49, 0x0f, 0x45, 0xfa,
+ 0x75, 0xf5,
+ BYTES_NOP3,
+ };
+
+ text_poke_early(addr + fineibt_preamble_bhi, magic, 9);
+
+ return;
+ }
+
+ text_poke_early(addr + fineibt_preamble_bhi,
+ text_gen_insn(CALL_INSN_OPCODE,
+ addr + fineibt_preamble_bhi,
+ __bhi_args[arity]),
+ CALL_INSN_SIZE);
+}
+
static int cfi_rewrite_preamble(s32 *start, s32 *end)
{
s32 *s;
@@ -1341,14 +1388,8 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
"kCFI preamble has wrong register at: %pS %*ph\n",
addr, 5, addr);
- if (!cfi_bhi || !arity)
- continue;
-
- text_poke_early(addr + fineibt_preamble_bhi,
- text_gen_insn(CALL_INSN_OPCODE,
- addr + fineibt_preamble_bhi,
- __bhi_args[arity]),
- CALL_INSN_SIZE);
+ if (cfi_bhi)
+ cfi_fineibt_bhi_preamble(addr, arity);
}
return 0;
@@ -1361,7 +1402,7 @@ static void cfi_rewrite_endbr(s32 *start, s32 *end)
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
- if (!is_endbr(addr + 16))
+ if (!exact_endbr(addr + 16))
continue;
poison_endbr(addr + 16);
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/ibt: Implement FineIBT-BHI mitigation
2025-02-24 12:37 ` [PATCH v4 09/10] x86/ibt: Implement FineIBT-BHI mitigation Peter Zijlstra
` (2 preceding siblings ...)
2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
@ 2025-02-26 12:54 ` tip-bot2 for Peter Zijlstra
2025-02-26 19:53 ` Peter Zijlstra
3 siblings, 1 reply; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 12:54 UTC (permalink / raw)
To: linux-tip-commits
Cc: Scott Constable, Peter Zijlstra (Intel), Ingo Molnar, Kees Cook,
x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: 0c92385dc05ee9637c04372ea95a11bbf6e010ff
Gitweb: https://git.kernel.org/tip/0c92385dc05ee9637c04372ea95a11bbf6e010ff
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:12 +01:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Wed, 26 Feb 2025 13:49:11 +01:00
x86/ibt: Implement FineIBT-BHI mitigation
While WAIT_FOR_ENDBR is specified to be a full speculation stop; it
has been shown that some implementations are 'leaky' to such an extend
that speculation can escape even the FineIBT preamble.
To deal with this, add additional hardening to the FineIBT preamble.
Notably, using a new LLVM feature:
https://github.com/llvm/llvm-project/commit/e223485c9b38a5579991b8cebb6a200153eee245
which encodes the number of arguments in the kCFI preamble's register.
Using this register<->arity mapping, have the FineIBT preamble CALL
into a stub clobbering the relevant argument registers in the
speculative case.
Scott sayeth thusly:
Microarchitectural attacks such as Branch History Injection (BHI) and
Intra-mode Branch Target Injection (IMBTI) [1] can cause an indirect
call to mispredict to an adversary-influenced target within the same
hardware domain (e.g., within the kernel). Instructions at the
mispredicted target may execute speculatively and potentially expose
kernel data (e.g., to a user-mode adversary) through a
microarchitectural covert channel such as CPU cache state.
CET-IBT [2] is a coarse-grained control-flow integrity (CFI) ISA
extension that enforces that each indirect call (or indirect jump)
must land on an ENDBR (end branch) instruction, even speculatively*.
FineIBT is a software technique that refines CET-IBT by associating
each function type with a 32-bit hash and enforcing (at the callee)
that the hash of the caller's function pointer type matches the hash
of the callee's function type. However, recent research [3] has
demonstrated that the conditional branch that enforces FineIBT's hash
check can be coerced to mispredict, potentially allowing an adversary
to speculatively bypass the hash check:
__cfi_foo:
ENDBR64
SUB R10d, 0x01234567
JZ foo # Even if the hash check fails and ZF=0, this branch could still mispredict as taken
UD2
foo:
...
The techniques demonstrated in [3] require the attacker to be able to
control the contents of at least one live register at the mispredicted
target. Therefore, this patch set introduces a sequence of CMOV
instructions at each indirect-callable target that poisons every live
register with data that the attacker cannot control whenever the
FineIBT hash check fails, thus mitigating any potential attack.
The security provided by this scheme has been discussed in detail on
an earlier thread [4].
[1] https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/branch-history-injection.html
[2] Intel Software Developer's Manual, Volume 1, Chapter 18
[3] https://www.vusec.net/projects/native-bhi/
[4] https://lore.kernel.org/lkml/20240927194925.707462984@infradead.org/
*There are some caveats for certain processors, see [1] for more info
Suggested-by: Scott Constable <scott.d.constable@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.820402212@infradead.org
---
Makefile | 3 +-
arch/x86/Kconfig | 8 ++-
arch/x86/include/asm/cfi.h | 6 ++-
arch/x86/kernel/alternative.c | 107 +++++++++++++++++++++++++++++----
arch/x86/net/bpf_jit_comp.c | 29 ++++++---
5 files changed, 134 insertions(+), 19 deletions(-)
diff --git a/Makefile b/Makefile
index 96407c1..f19431f 100644
--- a/Makefile
+++ b/Makefile
@@ -1014,6 +1014,9 @@ CC_FLAGS_CFI := -fsanitize=kcfi
ifdef CONFIG_CFI_ICALL_NORMALIZE_INTEGERS
CC_FLAGS_CFI += -fsanitize-cfi-icall-experimental-normalize-integers
endif
+ifdef CONFIG_FINEIBT_BHI
+ CC_FLAGS_CFI += -fsanitize-kcfi-arity
+endif
ifdef CONFIG_RUST
# Always pass -Zsanitizer-cfi-normalize-integers as CONFIG_RUST selects
# CONFIG_CFI_ICALL_NORMALIZE_INTEGERS.
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index c4175f4..5c27726 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2473,6 +2473,10 @@ config CC_HAS_RETURN_THUNK
config CC_HAS_ENTRY_PADDING
def_bool $(cc-option,-fpatchable-function-entry=16,16)
+config CC_HAS_KCFI_ARITY
+ def_bool $(cc-option,-fsanitize=kcfi -fsanitize-kcfi-arity)
+ depends on CC_IS_CLANG && !RUST
+
config FUNCTION_PADDING_CFI
int
default 59 if FUNCTION_ALIGNMENT_64B
@@ -2498,6 +2502,10 @@ config FINEIBT
depends on X86_KERNEL_IBT && CFI_CLANG && MITIGATION_RETPOLINE
select CALL_PADDING
+config FINEIBT_BHI
+ def_bool y
+ depends on FINEIBT && CC_HAS_KCFI_ARITY
+
config HAVE_CALL_THUNKS
def_bool y
depends on CC_HAS_ENTRY_PADDING && MITIGATION_RETHUNK && OBJTOOL
diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h
index 7c15c4b..2f6a01f 100644
--- a/arch/x86/include/asm/cfi.h
+++ b/arch/x86/include/asm/cfi.h
@@ -100,6 +100,7 @@ enum cfi_mode {
};
extern enum cfi_mode cfi_mode;
+extern bool cfi_bhi;
typedef u8 bhi_thunk[32];
extern bhi_thunk __bhi_args[];
@@ -129,6 +130,7 @@ static inline int cfi_get_offset(void)
#define cfi_get_offset cfi_get_offset
extern u32 cfi_get_func_hash(void *func);
+extern int cfi_get_func_arity(void *func);
#ifdef CONFIG_FINEIBT
extern bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type);
@@ -152,6 +154,10 @@ static inline u32 cfi_get_func_hash(void *func)
{
return 0;
}
+static inline int cfi_get_func_arity(void *func)
+{
+ return 0;
+}
#endif /* CONFIG_CFI_CLANG */
#if HAS_KERNEL_IBT == 1
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index c698c9e..b8d65d5 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -936,6 +936,7 @@ void __init_or_module apply_seal_endbr(s32 *start, s32 *end) { }
#endif
enum cfi_mode cfi_mode __ro_after_init = __CFI_DEFAULT;
+bool cfi_bhi __ro_after_init = false;
#ifdef CONFIG_CFI_CLANG
struct bpf_insn;
@@ -996,6 +997,21 @@ u32 cfi_get_func_hash(void *func)
return hash;
}
+
+int cfi_get_func_arity(void *func)
+{
+ bhi_thunk *target;
+ s32 disp;
+
+ if (cfi_mode != CFI_FINEIBT && !cfi_bhi)
+ return 0;
+
+ if (get_kernel_nofault(disp, func - 4))
+ return 0;
+
+ target = func + disp;
+ return target - __bhi_args;
+}
#endif
#ifdef CONFIG_FINEIBT
@@ -1053,6 +1069,12 @@ static __init int cfi_parse_cmdline(char *str)
} else {
pr_err("Ignoring paranoid; depends on fineibt.\n");
}
+ } else if (!strcmp(str, "bhi")) {
+ if (cfi_mode == CFI_FINEIBT) {
+ cfi_bhi = true;
+ } else {
+ pr_err("Ignoring bhi; depends on fineibt.\n");
+ }
} else {
pr_err("Ignoring unknown cfi option (%s).", str);
}
@@ -1105,6 +1127,7 @@ asm( ".pushsection .rodata \n"
"fineibt_preamble_start: \n"
" endbr64 \n"
" subl $0x12345678, %r10d \n"
+ "fineibt_preamble_bhi: \n"
" jne fineibt_preamble_start+6 \n"
ASM_NOP3
"fineibt_preamble_end: \n"
@@ -1112,9 +1135,11 @@ asm( ".pushsection .rodata \n"
);
extern u8 fineibt_preamble_start[];
+extern u8 fineibt_preamble_bhi[];
extern u8 fineibt_preamble_end[];
#define fineibt_preamble_size (fineibt_preamble_end - fineibt_preamble_start)
+#define fineibt_preamble_bhi (fineibt_preamble_bhi - fineibt_preamble_start)
#define fineibt_preamble_ud 6
#define fineibt_preamble_hash 7
@@ -1187,13 +1212,16 @@ extern u8 fineibt_paranoid_end[];
#define fineibt_paranoid_ind (fineibt_paranoid_ind - fineibt_paranoid_start)
#define fineibt_paranoid_ud 0xd
-static u32 decode_preamble_hash(void *addr)
+static u32 decode_preamble_hash(void *addr, int *reg)
{
u8 *p = addr;
- /* b8 78 56 34 12 mov $0x12345678,%eax */
- if (p[0] == 0xb8)
+ /* b8+reg 78 56 34 12 movl $0x12345678,\reg */
+ if (p[0] >= 0xb8 && p[0] < 0xc0) {
+ if (reg)
+ *reg = p[0] - 0xb8;
return *(u32 *)(addr + 1);
+ }
return 0; /* invalid hash value */
}
@@ -1202,11 +1230,11 @@ static u32 decode_caller_hash(void *addr)
{
u8 *p = addr;
- /* 41 ba 78 56 34 12 mov $0x12345678,%r10d */
+ /* 41 ba 88 a9 cb ed mov $(-0x12345678),%r10d */
if (p[0] == 0x41 && p[1] == 0xba)
return -*(u32 *)(addr + 2);
- /* e8 0c 78 56 34 12 jmp.d8 +12 */
+ /* e8 0c 88 a9 cb ed jmp.d8 +12 */
if (p[0] == JMP8_INSN_OPCODE && p[1] == fineibt_caller_jmp)
return -*(u32 *)(addr + 2);
@@ -1271,7 +1299,7 @@ static int cfi_rand_preamble(s32 *start, s32 *end)
void *addr = (void *)s + *s;
u32 hash;
- hash = decode_preamble_hash(addr);
+ hash = decode_preamble_hash(addr, NULL);
if (WARN(!hash, "no CFI hash found at: %pS %px %*ph\n",
addr, addr, 5, addr))
return -EINVAL;
@@ -1289,6 +1317,7 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
for (s = start; s < end; s++) {
void *addr = (void *)s + *s;
+ int arity;
u32 hash;
/*
@@ -1299,7 +1328,7 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
if (!is_endbr(addr + 16))
continue;
- hash = decode_preamble_hash(addr);
+ hash = decode_preamble_hash(addr, &arity);
if (WARN(!hash, "no CFI hash found at: %pS %px %*ph\n",
addr, addr, 5, addr))
return -EINVAL;
@@ -1307,6 +1336,19 @@ static int cfi_rewrite_preamble(s32 *start, s32 *end)
text_poke_early(addr, fineibt_preamble_start, fineibt_preamble_size);
WARN_ON(*(u32 *)(addr + fineibt_preamble_hash) != 0x12345678);
text_poke_early(addr + fineibt_preamble_hash, &hash, 4);
+
+ WARN_ONCE(!IS_ENABLED(CONFIG_FINEIBT_BHI) && arity,
+ "kCFI preamble has wrong register at: %pS %*ph\n",
+ addr, 5, addr);
+
+ if (!cfi_bhi || !arity)
+ continue;
+
+ text_poke_early(addr + fineibt_preamble_bhi,
+ text_gen_insn(CALL_INSN_OPCODE,
+ addr + fineibt_preamble_bhi,
+ __bhi_args[arity]),
+ CALL_INSN_SIZE);
}
return 0;
@@ -1474,8 +1516,9 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline,
cfi_rewrite_endbr(start_cfi, end_cfi);
if (builtin) {
- pr_info("Using %sFineIBT CFI\n",
- cfi_paranoid ? "paranoid " : "");
+ pr_info("Using %sFineIBT%s CFI\n",
+ cfi_paranoid ? "paranoid " : "",
+ cfi_bhi ? "+BHI" : "");
}
return;
@@ -1526,7 +1569,7 @@ static void poison_cfi(void *addr)
/*
* kCFI prefix should start with a valid hash.
*/
- if (!decode_preamble_hash(addr))
+ if (!decode_preamble_hash(addr, NULL))
break;
/*
@@ -1575,6 +1618,47 @@ Efault:
}
/*
+ * regs->ip points to one of the UD2 in __bhi_args[].
+ */
+static bool decode_fineibt_bhi(struct pt_regs *regs, unsigned long *target, u32 *type)
+{
+ unsigned long addr;
+ u32 hash;
+
+ if (!cfi_bhi)
+ return false;
+
+ if (regs->ip < (unsigned long)__bhi_args ||
+ regs->ip >= (unsigned long)__bhi_args_end)
+ return false;
+
+ /*
+ * Fetch the return address from the stack, this points to the
+ * FineIBT preamble. Since the CALL instruction is in the 5 last
+ * bytes of the preamble, the return address is in fact the target
+ * address.
+ */
+ __get_kernel_nofault(&addr, regs->sp, unsigned long, Efault);
+ *target = addr;
+
+ addr -= fineibt_preamble_size;
+ if (!exact_endbr((void *)addr))
+ return false;
+
+ __get_kernel_nofault(&hash, addr + fineibt_preamble_hash, u32, Efault);
+ *type = (u32)regs->r10 + hash;
+
+ /*
+ * The UD2 sites are constructed with a RET immediately following,
+ * as such the non-fatal case can use the regular fixup.
+ */
+ return true;
+
+Efault:
+ return false;
+}
+
+/*
* regs->ip points to a LOCK Jcc.d8 instruction from the fineibt_paranoid_start[]
* sequence.
*/
@@ -1605,6 +1689,9 @@ bool decode_fineibt_insn(struct pt_regs *regs, unsigned long *target, u32 *type)
if (decode_fineibt_paranoid(regs, target, type))
return true;
+ if (decode_fineibt_bhi(regs, target, type))
+ return true;
+
return decode_fineibt_preamble(regs, target, type);
}
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index ce033e6..72776dc 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -410,15 +410,20 @@ static void emit_nops(u8 **pprog, int len)
* Emit the various CFI preambles, see asm/cfi.h and the comments about FineIBT
* in arch/x86/kernel/alternative.c
*/
+static int emit_call(u8 **prog, void *func, void *ip);
-static void emit_fineibt(u8 **pprog, u32 hash)
+static void emit_fineibt(u8 **pprog, u8 *ip, u32 hash, int arity)
{
u8 *prog = *pprog;
EMIT_ENDBR();
EMIT3_off32(0x41, 0x81, 0xea, hash); /* subl $hash, %r10d */
- EMIT2(0x75, 0xf9); /* jne.d8 .-7 */
- EMIT3(0x0f, 0x1f, 0x00); /* nop3 */
+ if (cfi_bhi) {
+ emit_call(&prog, __bhi_args[arity], ip + 11);
+ } else {
+ EMIT2(0x75, 0xf9); /* jne.d8 .-7 */
+ EMIT3(0x0f, 0x1f, 0x00); /* nop3 */
+ }
EMIT_ENDBR_POISON();
*pprog = prog;
@@ -447,13 +452,13 @@ static void emit_kcfi(u8 **pprog, u32 hash)
*pprog = prog;
}
-static void emit_cfi(u8 **pprog, u32 hash)
+static void emit_cfi(u8 **pprog, u8 *ip, u32 hash, int arity)
{
u8 *prog = *pprog;
switch (cfi_mode) {
case CFI_FINEIBT:
- emit_fineibt(&prog, hash);
+ emit_fineibt(&prog, ip, hash, arity);
break;
case CFI_KCFI:
@@ -504,13 +509,17 @@ static void emit_prologue_tail_call(u8 **pprog, bool is_subprog)
* bpf_tail_call helper will skip the first X86_TAIL_CALL_OFFSET bytes
* while jumping to another program
*/
-static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf,
+static void emit_prologue(u8 **pprog, u8 *ip, u32 stack_depth, bool ebpf_from_cbpf,
bool tail_call_reachable, bool is_subprog,
bool is_exception_cb)
{
u8 *prog = *pprog;
- emit_cfi(&prog, is_subprog ? cfi_bpf_subprog_hash : cfi_bpf_hash);
+ if (is_subprog) {
+ emit_cfi(&prog, ip, cfi_bpf_subprog_hash, 5);
+ } else {
+ emit_cfi(&prog, ip, cfi_bpf_hash, 1);
+ }
/* BPF trampoline can be made to work without these nops,
* but let's waste 5 bytes for now and optimize later
*/
@@ -1479,7 +1488,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
detect_reg_usage(insn, insn_cnt, callee_regs_used);
- emit_prologue(&prog, stack_depth,
+ emit_prologue(&prog, image, stack_depth,
bpf_prog_was_classic(bpf_prog), tail_call_reachable,
bpf_is_subprog(bpf_prog), bpf_prog->aux->exception_cb);
/* Exception callback will clobber callee regs for its own use, and
@@ -3046,7 +3055,9 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
/*
* Indirect call for bpf_struct_ops
*/
- emit_cfi(&prog, cfi_get_func_hash(func_addr));
+ emit_cfi(&prog, image,
+ cfi_get_func_hash(func_addr),
+ cfi_get_func_arity(func_addr));
} else {
/*
* Direct-call fentry stub, as such it needs accounting for the
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [tip: x86/core] x86/bhi: Add BHI stubs
2025-02-24 12:37 ` [PATCH v4 08/10] x86: BHI stubs Peter Zijlstra
` (2 preceding siblings ...)
2025-02-26 12:04 ` [tip: x86/core] x86/bhi: Add " tip-bot2 for Peter Zijlstra
@ 2025-02-26 12:54 ` tip-bot2 for Peter Zijlstra
3 siblings, 0 replies; 56+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2025-02-26 12:54 UTC (permalink / raw)
To: linux-tip-commits
Cc: Peter Zijlstra (Intel), Ingo Molnar, Kees Cook, x86, linux-kernel
The following commit has been merged into the x86/core branch of tip:
Commit-ID: b815f6877d8063482fe745f098eeef632679aa8a
Gitweb: https://git.kernel.org/tip/b815f6877d8063482fe745f098eeef632679aa8a
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Mon, 24 Feb 2025 13:37:11 +01:00
Committer: Ingo Molnar <mingo@kernel.org>
CommitterDate: Wed, 26 Feb 2025 13:48:52 +01:00
x86/bhi: Add BHI stubs
Add an array of code thunks, to be called from the FineIBT preamble,
clobbering the first 'n' argument registers for speculative execution.
Notably the 0th entry will clobber no argument registers and will never
be used, it exists so the array can be naturally indexed, while the 7th
entry will clobber all the 6 argument registers and also RSP in order to
mess up stack based arguments.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kees Cook <kees@kernel.org>
Link: https://lore.kernel.org/r/20250224124200.717378681@infradead.org
---
arch/x86/include/asm/cfi.h | 4 +-
arch/x86/lib/Makefile | 3 +-
arch/x86/lib/bhi.S | 147 ++++++++++++++++++++++++++++++++++++-
3 files changed, 153 insertions(+), 1 deletion(-)
create mode 100644 arch/x86/lib/bhi.S
diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h
index 7dd5ab2..7c15c4b 100644
--- a/arch/x86/include/asm/cfi.h
+++ b/arch/x86/include/asm/cfi.h
@@ -101,6 +101,10 @@ enum cfi_mode {
extern enum cfi_mode cfi_mode;
+typedef u8 bhi_thunk[32];
+extern bhi_thunk __bhi_args[];
+extern bhi_thunk __bhi_args_end[];
+
struct pt_regs;
#ifdef CONFIG_CFI_CLANG
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 8a59c61..f453507 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -66,5 +66,6 @@ endif
lib-y += clear_page_64.o copy_page_64.o
lib-y += memmove_64.o memset_64.o
lib-y += copy_user_64.o copy_user_uncached_64.o
- lib-y += cmpxchg16b_emu.o
+ lib-y += cmpxchg16b_emu.o
+ lib-y += bhi.o
endif
diff --git a/arch/x86/lib/bhi.S b/arch/x86/lib/bhi.S
new file mode 100644
index 0000000..5889168
--- /dev/null
+++ b/arch/x86/lib/bhi.S
@@ -0,0 +1,147 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/linkage.h>
+#include <asm/unwind_hints.h>
+#include <asm/nospec-branch.h>
+
+/*
+ * Notably, the FineIBT preamble calling these will have ZF set and r10 zero.
+ *
+ * The very last element is in fact larger than 32 bytes, but since its the
+ * last element, this does not matter,
+ *
+ * There are 2 #UD sites, located between 0,1-2,3 and 4,5-6,7 such that they
+ * can be reached using Jcc.d8, these elements (1 and 5) have sufficiently
+ * big alignment holes for this to not stagger the array.
+ */
+
+.pushsection .noinstr.text, "ax"
+
+ .align 32
+SYM_CODE_START(__bhi_args)
+
+#ifdef CONFIG_FINEIBT_BHI
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_0, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_1, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ cmovne %r10, %rdi
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 8
+ ANNOTATE_REACHABLE
+.Lud_1: ud2
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_2, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_3, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_1
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_4, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_5, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ cmovne %r10, %r8
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 8
+ ANNOTATE_REACHABLE
+.Lud_2: ud2
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_6, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ cmovne %r10, %r8
+ cmovne %r10, %r9
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_7, SYM_L_LOCAL)
+ ANNOTATE_NOENDBR
+ UNWIND_HINT_FUNC
+ jne .Lud_2
+ cmovne %r10, %rdi
+ cmovne %r10, %rsi
+ cmovne %r10, %rdx
+ cmovne %r10, %rcx
+ cmovne %r10, %r8
+ cmovne %r10, %r9
+ cmovne %r10, %rsp
+ ANNOTATE_UNRET_SAFE
+ ret
+ int3
+
+#endif /* CONFIG_FINEIBT_BHI */
+
+ .align 32
+SYM_INNER_LABEL(__bhi_args_end, SYM_L_GLOBAL)
+ ANNOTATE_NOENDBR
+ nop /* Work around toolchain+objtool quirk */
+SYM_CODE_END(__bhi_args)
+
+.popsection
^ permalink raw reply related [flat|nested] 56+ messages in thread
* Re: [tip: x86/core] x86/ibt: Implement FineIBT-BHI mitigation
2025-02-26 12:54 ` tip-bot2 for Peter Zijlstra
@ 2025-02-26 19:53 ` Peter Zijlstra
2025-03-10 8:55 ` Peter Zijlstra
2025-03-10 16:00 ` Miguel Ojeda
0 siblings, 2 replies; 56+ messages in thread
From: Peter Zijlstra @ 2025-02-26 19:53 UTC (permalink / raw)
To: linux-kernel, ojeda
Cc: linux-tip-commits, Scott Constable, Ingo Molnar, Kees Cook, x86
On Wed, Feb 26, 2025 at 12:54:35PM -0000, tip-bot2 for Peter Zijlstra wrote:
> diff --git a/Makefile b/Makefile
> index 96407c1..f19431f 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1014,6 +1014,9 @@ CC_FLAGS_CFI := -fsanitize=kcfi
> ifdef CONFIG_CFI_ICALL_NORMALIZE_INTEGERS
> CC_FLAGS_CFI += -fsanitize-cfi-icall-experimental-normalize-integers
> endif
> +ifdef CONFIG_FINEIBT_BHI
> + CC_FLAGS_CFI += -fsanitize-kcfi-arity
> +endif
> ifdef CONFIG_RUST
> # Always pass -Zsanitizer-cfi-normalize-integers as CONFIG_RUST selects
> # CONFIG_CFI_ICALL_NORMALIZE_INTEGERS.
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index c4175f4..5c27726 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -2473,6 +2473,10 @@ config CC_HAS_RETURN_THUNK
> config CC_HAS_ENTRY_PADDING
> def_bool $(cc-option,-fpatchable-function-entry=16,16)
>
> +config CC_HAS_KCFI_ARITY
> + def_bool $(cc-option,-fsanitize=kcfi -fsanitize-kcfi-arity)
> + depends on CC_IS_CLANG && !RUST
> +
Miguel, can we work on fixing that !RUST dep?
> config FUNCTION_PADDING_CFI
> int
> default 59 if FUNCTION_ALIGNMENT_64B
> @@ -2498,6 +2502,10 @@ config FINEIBT
> depends on X86_KERNEL_IBT && CFI_CLANG && MITIGATION_RETPOLINE
> select CALL_PADDING
>
> +config FINEIBT_BHI
> + def_bool y
> + depends on FINEIBT && CC_HAS_KCFI_ARITY
> +
> config HAVE_CALL_THUNKS
> def_bool y
> depends on CC_HAS_ENTRY_PADDING && MITIGATION_RETHUNK && OBJTOOL
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [tip: x86/core] x86/ibt: Implement FineIBT-BHI mitigation
2025-02-26 19:53 ` Peter Zijlstra
@ 2025-03-10 8:55 ` Peter Zijlstra
2025-03-10 16:00 ` Miguel Ojeda
1 sibling, 0 replies; 56+ messages in thread
From: Peter Zijlstra @ 2025-03-10 8:55 UTC (permalink / raw)
To: linux-kernel, ojeda
Cc: linux-tip-commits, Scott Constable, Ingo Molnar, Kees Cook, x86
Ping -- anything I can do the help?
On Wed, Feb 26, 2025 at 08:53:08PM +0100, Peter Zijlstra wrote:
> On Wed, Feb 26, 2025 at 12:54:35PM -0000, tip-bot2 for Peter Zijlstra wrote:
>
> > diff --git a/Makefile b/Makefile
> > index 96407c1..f19431f 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -1014,6 +1014,9 @@ CC_FLAGS_CFI := -fsanitize=kcfi
> > ifdef CONFIG_CFI_ICALL_NORMALIZE_INTEGERS
> > CC_FLAGS_CFI += -fsanitize-cfi-icall-experimental-normalize-integers
> > endif
> > +ifdef CONFIG_FINEIBT_BHI
> > + CC_FLAGS_CFI += -fsanitize-kcfi-arity
> > +endif
> > ifdef CONFIG_RUST
> > # Always pass -Zsanitizer-cfi-normalize-integers as CONFIG_RUST selects
> > # CONFIG_CFI_ICALL_NORMALIZE_INTEGERS.
> > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> > index c4175f4..5c27726 100644
> > --- a/arch/x86/Kconfig
> > +++ b/arch/x86/Kconfig
> > @@ -2473,6 +2473,10 @@ config CC_HAS_RETURN_THUNK
> > config CC_HAS_ENTRY_PADDING
> > def_bool $(cc-option,-fpatchable-function-entry=16,16)
> >
> > +config CC_HAS_KCFI_ARITY
> > + def_bool $(cc-option,-fsanitize=kcfi -fsanitize-kcfi-arity)
> > + depends on CC_IS_CLANG && !RUST
> > +
>
> Miguel, can we work on fixing that !RUST dep?
>
> > config FUNCTION_PADDING_CFI
> > int
> > default 59 if FUNCTION_ALIGNMENT_64B
> > @@ -2498,6 +2502,10 @@ config FINEIBT
> > depends on X86_KERNEL_IBT && CFI_CLANG && MITIGATION_RETPOLINE
> > select CALL_PADDING
> >
> > +config FINEIBT_BHI
> > + def_bool y
> > + depends on FINEIBT && CC_HAS_KCFI_ARITY
> > +
> > config HAVE_CALL_THUNKS
> > def_bool y
> > depends on CC_HAS_ENTRY_PADDING && MITIGATION_RETHUNK && OBJTOOL
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [tip: x86/core] x86/ibt: Implement FineIBT-BHI mitigation
2025-02-26 19:53 ` Peter Zijlstra
2025-03-10 8:55 ` Peter Zijlstra
@ 2025-03-10 16:00 ` Miguel Ojeda
2025-03-10 16:02 ` Peter Zijlstra
1 sibling, 1 reply; 56+ messages in thread
From: Miguel Ojeda @ 2025-03-10 16:00 UTC (permalink / raw)
To: Peter Zijlstra, Ramon de C Valle, Matthew Maurer
Cc: linux-kernel, ojeda, linux-tip-commits, Scott Constable,
Ingo Molnar, Kees Cook, x86, Sami Tolvanen, Alice Ryhl
On Wed, Feb 26, 2025 at 8:53 PM Peter Zijlstra <peterz@infradead.org> wrote:
>
> On Wed, Feb 26, 2025 at 12:54:35PM -0000, tip-bot2 for Peter Zijlstra wrote:
>
> > +config CC_HAS_KCFI_ARITY
> > + def_bool $(cc-option,-fsanitize=kcfi -fsanitize-kcfi-arity)
> > + depends on CC_IS_CLANG && !RUST
> > +
>
> Miguel, can we work on fixing that !RUST dep?
Thanks for the ping Peter -- we discussed `rustc` in the couple PRs
that added it to LLVM back then, and I think the conclusion was that
it shouldn't be a fundamental problem to add it to `rustc`.
From a quick look, the Clang flag that eventually landed just emits
one more `llvm.module.flags` and LLVM takes care of the rest. So it
should be straightforward to add a `-Csanitize-kcfi-arity` in `rustc`
and then pass it at the same time to both Clang and `rustc` in the
kernel.
But I may be missing something -- Cc'ing Ramon and Matthew, since they
are the ones behind sanitizers and kCFI in upstream Rust.
I added it to our list, and created an issue in upstream Rust for it:
https://github.com/rust-lang/rust/issues/138311
https://github.com/Rust-for-Linux/linux/issues/355
I will also mention it in the meeting with upstream Rust in a couple days.
Cheers,
Miguel
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [tip: x86/core] x86/ibt: Implement FineIBT-BHI mitigation
2025-03-10 16:00 ` Miguel Ojeda
@ 2025-03-10 16:02 ` Peter Zijlstra
2025-03-11 19:09 ` Ramon de C Valle
0 siblings, 1 reply; 56+ messages in thread
From: Peter Zijlstra @ 2025-03-10 16:02 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Ramon de C Valle, Matthew Maurer, linux-kernel, ojeda,
linux-tip-commits, Scott Constable, Ingo Molnar, Kees Cook, x86,
Sami Tolvanen, Alice Ryhl
On Mon, Mar 10, 2025 at 05:00:47PM +0100, Miguel Ojeda wrote:
> On Wed, Feb 26, 2025 at 8:53 PM Peter Zijlstra <peterz@infradead.org> wrote:
> >
> > On Wed, Feb 26, 2025 at 12:54:35PM -0000, tip-bot2 for Peter Zijlstra wrote:
> >
> > > +config CC_HAS_KCFI_ARITY
> > > + def_bool $(cc-option,-fsanitize=kcfi -fsanitize-kcfi-arity)
> > > + depends on CC_IS_CLANG && !RUST
> > > +
> >
> > Miguel, can we work on fixing that !RUST dep?
>
> Thanks for the ping Peter -- we discussed `rustc` in the couple PRs
> that added it to LLVM back then, and I think the conclusion was that
> it shouldn't be a fundamental problem to add it to `rustc`.
>
> From a quick look, the Clang flag that eventually landed just emits
> one more `llvm.module.flags` and LLVM takes care of the rest. So it
> should be straightforward to add a `-Csanitize-kcfi-arity` in `rustc`
> and then pass it at the same time to both Clang and `rustc` in the
> kernel.
>
> But I may be missing something -- Cc'ing Ramon and Matthew, since they
> are the ones behind sanitizers and kCFI in upstream Rust.
>
> I added it to our list, and created an issue in upstream Rust for it:
>
> https://github.com/rust-lang/rust/issues/138311
> https://github.com/Rust-for-Linux/linux/issues/355
>
> I will also mention it in the meeting with upstream Rust in a couple days.
Thanks!, let me know if there's anything I can do. I'm happy to test
patches.
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [tip: x86/core] x86/ibt: Implement FineIBT-BHI mitigation
2025-03-10 16:02 ` Peter Zijlstra
@ 2025-03-11 19:09 ` Ramon de C Valle
2025-03-11 19:41 ` Miguel Ojeda
0 siblings, 1 reply; 56+ messages in thread
From: Ramon de C Valle @ 2025-03-11 19:09 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Miguel Ojeda, Matthew Maurer, linux-kernel, ojeda,
linux-tip-commits, Scott Constable, Ingo Molnar, Kees Cook, x86,
Sami Tolvanen, Alice Ryhl
On Mon, Mar 10, 2025 at 9:04 AM Peter Zijlstra <peterz@infradead.org> wrote:
>
> On Mon, Mar 10, 2025 at 05:00:47PM +0100, Miguel Ojeda wrote:
> > On Wed, Feb 26, 2025 at 8:53 PM Peter Zijlstra <peterz@infradead.org> wrote:
> > >
> > > On Wed, Feb 26, 2025 at 12:54:35PM -0000, tip-bot2 for Peter Zijlstra wrote:
> > >
> > > > +config CC_HAS_KCFI_ARITY
> > > > + def_bool $(cc-option,-fsanitize=kcfi -fsanitize-kcfi-arity)
> > > > + depends on CC_IS_CLANG && !RUST
> > > > +
> > >
> > > Miguel, can we work on fixing that !RUST dep?
> >
> > Thanks for the ping Peter -- we discussed `rustc` in the couple PRs
> > that added it to LLVM back then, and I think the conclusion was that
> > it shouldn't be a fundamental problem to add it to `rustc`.
> >
> > From a quick look, the Clang flag that eventually landed just emits
> > one more `llvm.module.flags` and LLVM takes care of the rest. So it
> > should be straightforward to add a `-Csanitize-kcfi-arity` in `rustc`
> > and then pass it at the same time to both Clang and `rustc` in the
> > kernel.
> >
> > But I may be missing something -- Cc'ing Ramon and Matthew, since they
> > are the ones behind sanitizers and kCFI in upstream Rust.
> >
> > I added it to our list, and created an issue in upstream Rust for it:
> >
> > https://github.com/rust-lang/rust/issues/138311
> > https://github.com/Rust-for-Linux/linux/issues/355
> >
> > I will also mention it in the meeting with upstream Rust in a couple days.
>
> Thanks!, let me know if there's anything I can do. I'm happy to test
> patches.
I've submitted a PR for it:
https://github.com/rust-lang/rust/pull/138368. Let me know if you're
able to give it a try.
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [tip: x86/core] x86/ibt: Implement FineIBT-BHI mitigation
2025-03-11 19:09 ` Ramon de C Valle
@ 2025-03-11 19:41 ` Miguel Ojeda
2025-03-11 20:23 ` Ramon de C Valle
0 siblings, 1 reply; 56+ messages in thread
From: Miguel Ojeda @ 2025-03-11 19:41 UTC (permalink / raw)
To: Ramon de C Valle
Cc: Peter Zijlstra, Matthew Maurer, linux-kernel, ojeda,
linux-tip-commits, Scott Constable, Ingo Molnar, Kees Cook, x86,
Sami Tolvanen, Alice Ryhl
On Tue, Mar 11, 2025 at 8:09 PM Ramon de C Valle <rcvalle@google.com> wrote:
>
> I've submitted a PR for it:
> https://github.com/rust-lang/rust/pull/138368. Let me know if you're
> able to give it a try.
Thanks Ramon, that was quick!
Left a comment there and linked it -- if you meant to ask Peter, then
I guess it would be easiest for him to use the first nightly that has
it as a `-Z` flag.
i.e. I think it is simple enough to land it as-is, especially if we
add the quick check I suggested.
Cheers,
Miguel
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [tip: x86/core] x86/ibt: Implement FineIBT-BHI mitigation
2025-03-11 19:41 ` Miguel Ojeda
@ 2025-03-11 20:23 ` Ramon de C Valle
2025-03-12 9:16 ` Peter Zijlstra
0 siblings, 1 reply; 56+ messages in thread
From: Ramon de C Valle @ 2025-03-11 20:23 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Peter Zijlstra, Matthew Maurer, linux-kernel, ojeda,
linux-tip-commits, Scott Constable, Ingo Molnar, Kees Cook, x86,
Sami Tolvanen, Alice Ryhl
On Tue, Mar 11, 2025 at 12:41 PM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> On Tue, Mar 11, 2025 at 8:09 PM Ramon de C Valle <rcvalle@google.com> wrote:
> >
> > I've submitted a PR for it:
> > https://github.com/rust-lang/rust/pull/138368. Let me know if you're
> > able to give it a try.
>
> Thanks Ramon, that was quick!
>
> Left a comment there and linked it -- if you meant to ask Peter, then
> I guess it would be easiest for him to use the first nightly that has
> it as a `-Z` flag.
>
> i.e. I think it is simple enough to land it as-is, especially if we
> add the quick check I suggested.
Left a note there. Let me know what you think. Yes, I guess we could
just check the next nightly that has those changes.
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [tip: x86/core] x86/ibt: Implement FineIBT-BHI mitigation
2025-03-11 20:23 ` Ramon de C Valle
@ 2025-03-12 9:16 ` Peter Zijlstra
2025-03-12 11:36 ` Miguel Ojeda
0 siblings, 1 reply; 56+ messages in thread
From: Peter Zijlstra @ 2025-03-12 9:16 UTC (permalink / raw)
To: Ramon de C Valle
Cc: Miguel Ojeda, Matthew Maurer, linux-kernel, ojeda,
linux-tip-commits, Scott Constable, Ingo Molnar, Kees Cook, x86,
Sami Tolvanen, Alice Ryhl
On Tue, Mar 11, 2025 at 01:23:39PM -0700, Ramon de C Valle wrote:
> On Tue, Mar 11, 2025 at 12:41 PM Miguel Ojeda
> <miguel.ojeda.sandonis@gmail.com> wrote:
> >
> > On Tue, Mar 11, 2025 at 8:09 PM Ramon de C Valle <rcvalle@google.com> wrote:
> > >
> > > I've submitted a PR for it:
> > > https://github.com/rust-lang/rust/pull/138368. Let me know if you're
> > > able to give it a try.
> >
> > Thanks Ramon, that was quick!
> >
> > Left a comment there and linked it -- if you meant to ask Peter, then
> > I guess it would be easiest for him to use the first nightly that has
> > it as a `-Z` flag.
> >
> > i.e. I think it is simple enough to land it as-is, especially if we
> > add the quick check I suggested.
>
> Left a note there. Let me know what you think. Yes, I guess we could
> just check the next nightly that has those changes.
The rust-log-analyzer seems to suggest the nightly build failed?
Suppose it didn't fail, where do I find it?
I normally build llvm toolchains using tc-build, but it seems rust is
not actually part of llvm?
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [tip: x86/core] x86/ibt: Implement FineIBT-BHI mitigation
2025-03-12 9:16 ` Peter Zijlstra
@ 2025-03-12 11:36 ` Miguel Ojeda
2025-03-19 0:04 ` Nathan Chancellor
0 siblings, 1 reply; 56+ messages in thread
From: Miguel Ojeda @ 2025-03-12 11:36 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Ramon de C Valle, Matthew Maurer, linux-kernel, ojeda,
linux-tip-commits, Scott Constable, Ingo Molnar, Kees Cook, x86,
Sami Tolvanen, Alice Ryhl, Nathan Chancellor
On Wed, Mar 12, 2025 at 10:16 AM Peter Zijlstra <peterz@infradead.org> wrote:
>
> The rust-log-analyzer seems to suggest the nightly build failed?
>
> Suppose it didn't fail, where do I find it?
Ah, sorry for the confusion -- by "nightly" here I meant the toolchain
that gets built and distributed by the Rust project.
To get one, we need the PR to land first, and then we can use the new
flag. It is easy to land such a PR/feature because it lands as an
"unstable feature", i.e. meant for testing and so on only. So we can
get quickly "proper" toolchains (i.e. tested and built like the
full/normal releases are), and if everything checks out, then upstream
Rust can commit to stabilize the feature later on.
That is why I suggested to wait for that, since the PR seemed
straightforward to land to me, and thus it could land soon.
I don't know if there may be a way to pick up the toolchains that
their CI built for testing PRs, though. It is not too hard to build
from scratch anyway if you want to do so -- I can also build it for
you if you want to test right away before it lands. Otherwise, I can
ping you when the nightly toolchain is ready.
> I normally build llvm toolchains using tc-build, but it seems rust is
> not actually part of llvm?
Yeah, Rust uses LLVM but is not part of the LLVM project.
But I think we could have support to build Rust there easily -- I
discussed it with Nathan (Cc'd) in the past. Currently, for the
LLVM+Rust toolchains he provides in kernel.org, he just bundles the
upstream Rust binaries AFAIR -- and IIRC he uses tc-build to drive
that build, so if we do that we could also "easily" get the full chain
in kernel.org too ("easily" if we ignore doing the PGO dance for the
Rust side etc. and assuming the building time/resources makes it
doable, which I don't know about).
If that is correct, I could take a look into adding a simple Rust
build to tc-build (i.e. without PGO etc.).
Cheers,
Miguel
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [tip: x86/core] x86/ibt: Implement FineIBT-BHI mitigation
2025-03-12 11:36 ` Miguel Ojeda
@ 2025-03-19 0:04 ` Nathan Chancellor
0 siblings, 0 replies; 56+ messages in thread
From: Nathan Chancellor @ 2025-03-19 0:04 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Peter Zijlstra, Ramon de C Valle, Matthew Maurer, linux-kernel,
ojeda, linux-tip-commits, Scott Constable, Ingo Molnar, Kees Cook,
x86, Sami Tolvanen, Alice Ryhl
On Wed, Mar 12, 2025 at 12:36:42PM +0100, Miguel Ojeda wrote:
> On Wed, Mar 12, 2025 at 10:16 AM Peter Zijlstra <peterz@infradead.org> wrote:
> > I normally build llvm toolchains using tc-build, but it seems rust is
> > not actually part of llvm?
>
> Yeah, Rust uses LLVM but is not part of the LLVM project.
>
> But I think we could have support to build Rust there easily -- I
> discussed it with Nathan (Cc'd) in the past. Currently, for the
> LLVM+Rust toolchains he provides in kernel.org, he just bundles the
> upstream Rust binaries AFAIR -- and IIRC he uses tc-build to drive
> that build, so if we do that we could also "easily" get the full chain
> in kernel.org too ("easily" if we ignore doing the PGO dance for the
> Rust side etc. and assuming the building time/resources makes it
> doable, which I don't know about).
>
> If that is correct, I could take a look into adding a simple Rust
> build to tc-build (i.e. without PGO etc.).
Right, tc-build is used to build the toolchain but I have another build
wrapper around that to build the toolchain in a Debian bullseye
userspace for compatibility with glibc 2.28 and newer:
https://github.com/nathanchance/env/tree/c19e35f39080a961a762a6c486ca2b2077ffc4ef/python/pgo-llvm-builder
That is where I had initially considered wiring it up when we last
talked but wiring it up in tc-build would probably be better/cleaner,
especially with the rewrite I did two years ago. I could envision
tc_build/rust.py for example, then either integrating it into
build-llvm.py or have a separate standalone build-rust.py, like
binutils.
Cheers,
Nathan
^ permalink raw reply [flat|nested] 56+ messages in thread
end of thread, other threads:[~2025-03-19 0:04 UTC | newest]
Thread overview: 56+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-24 12:37 [PATCH v4 00/10] x86/ibt: FineIBT-BHI Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 01/10] x86/cfi: Add warn option Peter Zijlstra
2025-02-24 18:57 ` Kees Cook
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/cfi: Add 'cfi=warn' boot option tip-bot2 for Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 02/10] x86/ibt: Add exact_endbr() helper Peter Zijlstra
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 03/10] x86/traps: Decode 0xEA #UD Peter Zijlstra
2025-02-24 18:58 ` Kees Cook
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/traps: Decode 0xEA instructions as #UD tip-bot2 for Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 04/10] x86/traps: Allow custom fixups in handle_bug() Peter Zijlstra
2025-02-24 18:59 ` Kees Cook
2025-02-25 8:54 ` Peter Zijlstra
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 05/10] x86/ibt: Optimize FineIBT sequence Peter Zijlstra
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/ibt: Optimize the FineIBT instruction sequence tip-bot2 for Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 06/10] x86/traps: Decode LOCK Jcc.d8 #UD Peter Zijlstra
2025-02-24 21:46 ` David Laight
2025-02-25 18:33 ` Kees Cook
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/traps: Decode LOCK Jcc.d8 as #UD tip-bot2 for Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 07/10] x86/ibt: Add paranoid FineIBT mode Peter Zijlstra
2025-02-24 19:00 ` Kees Cook
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 08/10] x86: BHI stubs Peter Zijlstra
2025-02-24 19:01 ` Kees Cook
2025-02-25 8:52 ` Peter Zijlstra
2025-02-25 18:31 ` Kees Cook
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/bhi: Add " tip-bot2 for Peter Zijlstra
2025-02-26 12:54 ` tip-bot2 for Peter Zijlstra
2025-02-24 12:37 ` [PATCH v4 09/10] x86/ibt: Implement FineIBT-BHI mitigation Peter Zijlstra
2025-02-25 9:12 ` Peter Zijlstra
2025-02-26 0:04 ` Constable, Scott D
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` tip-bot2 for Peter Zijlstra
2025-02-26 12:54 ` tip-bot2 for Peter Zijlstra
2025-02-26 19:53 ` Peter Zijlstra
2025-03-10 8:55 ` Peter Zijlstra
2025-03-10 16:00 ` Miguel Ojeda
2025-03-10 16:02 ` Peter Zijlstra
2025-03-11 19:09 ` Ramon de C Valle
2025-03-11 19:41 ` Miguel Ojeda
2025-03-11 20:23 ` Ramon de C Valle
2025-03-12 9:16 ` Peter Zijlstra
2025-03-12 11:36 ` Miguel Ojeda
2025-03-19 0:04 ` Nathan Chancellor
2025-02-24 12:37 ` [PATCH v4 10/10] x86/ibt: Optimize fineibt-bhi arity 1 case Peter Zijlstra
2025-02-26 10:54 ` [tip: x86/core] " tip-bot2 for Peter Zijlstra
2025-02-26 12:04 ` [tip: x86/core] x86/ibt: Optimize the " tip-bot2 for Peter Zijlstra
2025-02-26 12:54 ` tip-bot2 for Peter Zijlstra
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox