summaryrefslogtreecommitdiff
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-18 14:08:57 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-18 14:08:57 -0700
commitd5b550edadab6810653f287715a0d696306b6ae0 (patch)
treebe38aaf138393478dd90567260351605c35100f0 /arch/x86/kernel
parent3dd1f7447f4f989b3a348cdc347b15397d03bebc (diff)
parentd824ed1307680dd482f607b0e707c575f70668c4 (diff)
Merge tag 'x86-core-2026-08-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 core updates from Ingo Molnar: - Optimize the kcfi call sequence (Peter Zijlstra) - Use sfence for wmb() if SSE is available (Yao Zi) * tag 'x86-core-2026-08-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/locking: Use sfence for wmb() if SSE is available x86/kcfi: Optimize call sequence
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/alternative.c21
-rw-r--r--arch/x86/kernel/cfi.c11
2 files changed, 29 insertions, 3 deletions
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 62936a3bde19..ba7d2059a709 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -1356,6 +1356,20 @@ early_param("cfi", cfi_parse_cmdline);
* "Make conditional jumps most often not taken: The efficiency and throughput
* for not-taken branches is better than for taken branches on most
* processors. Therefore, it is good to place the most frequent branch first"
+ *
+ * NOTE: Update the kCFI caller sequence to make use of this observation:
+ *
+ * kCFI kCFI-OPT
+ *
+ * caller: caller:
+ * movl $(-0x12345678),%r10d // 6 movl $(-0x12345678),%r10d // 6
+ * addl $-15(%r11),%r10d // 4 addl $-15(%r11),%r10d // 4
+ * je 1f // 2 jne . + 3 // 2
+ * ud2 // 2 test $0xd6, %al // 2
+ * 1: cs call __x86_indirect_thunk_r11 // 6 1: cs call __x86_indirect_thunk_r11 // 6
+ *
+ * This new test clobbers eflags, but those are clobbered by the hash test
+ * anyway.
*/
/*
@@ -1518,8 +1532,9 @@ static int cfi_disable_callers(s32 *start, s32 *end)
static int cfi_enable_callers(s32 *start, s32 *end)
{
/*
- * Re-enable kCFI, undo what cfi_disable_callers() did.
+ * Re-enable (and update) kCFI, undo what cfi_disable_callers() did.
*/
+ const u8 udne[] = { 0x75, 0x01, 0xa8, 0xd6 };
const u8 mov[] = { 0x41, 0xba };
s32 *s;
@@ -1532,6 +1547,10 @@ static int cfi_enable_callers(s32 *start, s32 *end)
if (!hash) /* nocfi callers */
continue;
+ /*
+ * See the kCFI/FineIBT comment above -- update note.
+ */
+ text_poke_early(addr + 10, udne, 4);
text_poke_early(addr, mov, 2);
}
diff --git a/arch/x86/kernel/cfi.c b/arch/x86/kernel/cfi.c
index 638eb5c933e0..1df26dfdce08 100644
--- a/arch/x86/kernel/cfi.c
+++ b/arch/x86/kernel/cfi.c
@@ -72,8 +72,15 @@ enum bug_trap_type handle_cfi_failure(struct pt_regs *regs)
switch (cfi_mode) {
case CFI_KCFI:
- if (!is_cfi_trap(addr))
- return BUG_TRAP_TYPE_NONE;
+ if (!is_cfi_trap(addr)) {
+ /*
+ * The updated kCFI sequence has "test $0xd6, %al" instead of
+ * "ud2", adjust the offset.
+ */
+ addr -= 1;
+ if (!is_cfi_trap(addr))
+ return BUG_TRAP_TYPE_NONE;
+ }
if (!decode_cfi_insn(regs, &target, &type))
return report_cfi_failure_noaddr(regs, addr);