* [PATCH 0/3] x86/cfi: Fix a few kCFI issues found with GCC
@ 2026-10-12 9:04 Kees Cook
2026-10-12 9:04 ` [PATCH 1/3] x86/kcfi: Decode the kCFI check from the trap address Kees Cook
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Kees Cook @ 2026-10-12 9:04 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Kees Cook, Josh Poimboeuf, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, H. Peter Anvin, Sami Tolvanen,
Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
x86, llvm, linux-kernel, linux-hardening
Hi!
While testing x86 kernels built by GCC with the coming kCFI patches I
tripped over three problems. Since the kCFI call sequence was optimized
in v7.3-rc1, the trap handler decodes the check one byte off, so a
kCFI failure in a CONFIG_FINEIBT=y kernel running in kCFI mode reports
whatever %rbx holds as the target, with Clang as well as GCC (1/3). GNU
as warns about the "cs" prefix in the FineIBT paranoid caller template,
which Clang's integrated assembler accepts silently (2/3). And objtool's
kCFI check treats GCC's jump-table jump for the BPF interpreter's computed
goto as an unchecked indirect call (3/3).
Thanks!
-Kees
Kees Cook (3):
x86/kcfi: Decode the kCFI check from the trap address
x86/kcfi: Emit the FineIBT paranoid "cs" prefix as a byte
objtool: Skip jump table jumps in the kCFI indirect call check
arch/x86/kernel/alternative.c | 3 ++-
arch/x86/kernel/cfi.c | 14 +++++++-------
tools/objtool/check.c | 8 ++++++++
3 files changed, 17 insertions(+), 8 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 1/3] x86/kcfi: Decode the kCFI check from the trap address 2026-10-12 9:04 [PATCH 0/3] x86/cfi: Fix a few kCFI issues found with GCC Kees Cook @ 2026-10-12 9:04 ` Kees Cook 2026-10-12 9:59 ` [tip: x86/urgent] " tip-bot2 for Kees Cook 2026-10-12 9:04 ` [PATCH 2/3] x86/kcfi: Emit the FineIBT paranoid "cs" prefix as a byte Kees Cook 2026-10-12 9:04 ` [PATCH 3/3] objtool: Skip jump table jumps in the kCFI indirect call check Kees Cook 2 siblings, 1 reply; 10+ messages in thread From: Kees Cook @ 2026-10-12 9:04 UTC (permalink / raw) To: Peter Zijlstra Cc: Kees Cook, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin, Sami Tolvanen, Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt, x86, llvm, linux-kernel, linux-hardening Since commit b2250d63e6422 ("x86/kcfi: Optimize call sequence"), a CONFIG_FINEIBT=y kernel running in kCFI mode rewrites each kCFI call site at boot so that a failed check traps on the 0xd6 byte of "test $0xd6, %al", one byte past where the compiler's "ud2" was. handle_cfi_failure() steps "addr" back one byte to find the trap in .kcfi_traps, but decode_cfi_insn() still decodes from regs->ip, so it reads each instruction starting at its second byte. "movl $-<id>, %r10d" then decodes as "movl $-<id>, %edx", so the reported type is right by accident, but "addl -15(%r11), %r10d" decodes as "addl -15(%rbx), %edx", so the reported target is whatever %rbx holds: CFI failure at lkdtm_indirect_call+0x16/0x20 (target: 0x12; expected type: 0xc79a2d1b) Pass the adjusted address to decode_cfi_insn() and decode from it. Tested ARCH=x86_64 defconfig with CONFIG_CFI=y and CONFIG_LKDTM=y under QEMU, with LKDTM's CFI_FORWARD_PROTO and both Clang 24.0.0git and GCC 17.0.0 (experimental, with the kCFI series). With CONFIG_FINEIBT=y in kCFI mode, the report gives %rbx as the target without this change, and the expected lkdtm_increment_int() with it. With cfi=fineibt, with cfi=fineibt,paranoid, and with CONFIG_FINEIBT=n, it gives lkdtm_increment_int() both with and without this change. Fixes: b2250d63e6422 ("x86/kcfi: Optimize call sequence") Assisted-by: LLM Signed-off-by: Kees Cook <kees@kernel.org> --- arch/x86/kernel/cfi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/cfi.c b/arch/x86/kernel/cfi.c index 1df26dfdce08..8e5c4ed264a0 100644 --- a/arch/x86/kernel/cfi.c +++ b/arch/x86/kernel/cfi.c @@ -10,11 +10,11 @@ #include <asm/insn-eval.h> /* - * Returns the target address and the expected type when regs->ip points + * Returns the target address and the expected type when addr points * to a compiler-generated CFI trap. */ -static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target, - u32 *type) +static bool decode_cfi_insn(struct pt_regs *regs, unsigned long addr, + unsigned long *target, u32 *type) { char buffer[MAX_INSN_SIZE]; struct insn insn; @@ -29,13 +29,13 @@ static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target, * movl -<id>, %r10d ; 6 bytes * addl -<pos>(%reg), %r10d; 4 bytes * je .Ltmp1 ; 2 bytes - * ud2 ; <- regs->ip + * ud2 ; <- addr * .Ltmp1: * * We can decode the expected type and the target address from the * movl/addl instructions. */ - if (copy_from_kernel_nofault(buffer, (void *)regs->ip - 12, MAX_INSN_SIZE)) + if (copy_from_kernel_nofault(buffer, (void *)addr - 12, MAX_INSN_SIZE)) return false; if (insn_decode_kernel(&insn, &buffer[offset])) return false; @@ -44,7 +44,7 @@ static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target, *type = -(u32)insn.immediate.value; - if (copy_from_kernel_nofault(buffer, (void *)regs->ip - 6, MAX_INSN_SIZE)) + if (copy_from_kernel_nofault(buffer, (void *)addr - 6, MAX_INSN_SIZE)) return false; if (insn_decode_kernel(&insn, &buffer[offset])) return false; @@ -82,7 +82,7 @@ enum bug_trap_type handle_cfi_failure(struct pt_regs *regs) return BUG_TRAP_TYPE_NONE; } - if (!decode_cfi_insn(regs, &target, &type)) + if (!decode_cfi_insn(regs, addr, &target, &type)) return report_cfi_failure_noaddr(regs, addr); break; -- 2.55.0 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [tip: x86/urgent] x86/kcfi: Decode the kCFI check from the trap address 2026-10-12 9:04 ` [PATCH 1/3] x86/kcfi: Decode the kCFI check from the trap address Kees Cook @ 2026-10-12 9:59 ` tip-bot2 for Kees Cook 0 siblings, 0 replies; 10+ messages in thread From: tip-bot2 for Kees Cook @ 2026-10-12 9:59 UTC (permalink / raw) To: linux-tip-commits; +Cc: Kees Cook, Peter Zijlstra (Intel), x86, linux-kernel The following commit has been merged into the x86/urgent branch of tip: Commit-ID: 4505a262deae7df06e33617dfc104d5541eec91d Gitweb: https://git.kernel.org/tip/4505a262deae7df06e33617dfc104d5541eec91d Author: Kees Cook <kees@kernel.org> AuthorDate: Mon, 12 Oct 2026 02:04:24 -07:00 Committer: Peter Zijlstra <peterz@infradead.org> CommitterDate: Mon, 12 Oct 2026 11:47:32 +02:00 x86/kcfi: Decode the kCFI check from the trap address Since commit b2250d63e6422 ("x86/kcfi: Optimize call sequence"), a CONFIG_FINEIBT=y kernel running in kCFI mode rewrites each kCFI call site at boot so that a failed check traps on the 0xd6 byte of "test $0xd6, %al", one byte past where the compiler's "ud2" was. handle_cfi_failure() steps "addr" back one byte to find the trap in .kcfi_traps, but decode_cfi_insn() still decodes from regs->ip, so it reads each instruction starting at its second byte. "movl $-<id>, %r10d" then decodes as "movl $-<id>, %edx", so the reported type is right by accident, but "addl -15(%r11), %r10d" decodes as "addl -15(%rbx), %edx", so the reported target is whatever %rbx holds: CFI failure at lkdtm_indirect_call+0x16/0x20 (target: 0x12; expected type: 0xc79a2d1b) Pass the adjusted address to decode_cfi_insn() and decode from it. Tested ARCH=x86_64 defconfig with CONFIG_CFI=y and CONFIG_LKDTM=y under QEMU, with LKDTM's CFI_FORWARD_PROTO and both Clang 24.0.0git and GCC 17.0.0 (experimental, with the kCFI series). With CONFIG_FINEIBT=y in kCFI mode, the report gives %rbx as the target without this change, and the expected lkdtm_increment_int() with it. With cfi=fineibt, with cfi=fineibt,paranoid, and with CONFIG_FINEIBT=n, it gives lkdtm_increment_int() both with and without this change. Fixes: b2250d63e6422 ("x86/kcfi: Optimize call sequence") Assisted-by: LLM Signed-off-by: Kees Cook <kees@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/20261012090436.1676525-1-kees@kernel.org --- arch/x86/kernel/cfi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/cfi.c b/arch/x86/kernel/cfi.c index 1df26df..8e5c4ed 100644 --- a/arch/x86/kernel/cfi.c +++ b/arch/x86/kernel/cfi.c @@ -10,11 +10,11 @@ #include <asm/insn-eval.h> /* - * Returns the target address and the expected type when regs->ip points + * Returns the target address and the expected type when addr points * to a compiler-generated CFI trap. */ -static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target, - u32 *type) +static bool decode_cfi_insn(struct pt_regs *regs, unsigned long addr, + unsigned long *target, u32 *type) { char buffer[MAX_INSN_SIZE]; struct insn insn; @@ -29,13 +29,13 @@ static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target, * movl -<id>, %r10d ; 6 bytes * addl -<pos>(%reg), %r10d; 4 bytes * je .Ltmp1 ; 2 bytes - * ud2 ; <- regs->ip + * ud2 ; <- addr * .Ltmp1: * * We can decode the expected type and the target address from the * movl/addl instructions. */ - if (copy_from_kernel_nofault(buffer, (void *)regs->ip - 12, MAX_INSN_SIZE)) + if (copy_from_kernel_nofault(buffer, (void *)addr - 12, MAX_INSN_SIZE)) return false; if (insn_decode_kernel(&insn, &buffer[offset])) return false; @@ -44,7 +44,7 @@ static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target, *type = -(u32)insn.immediate.value; - if (copy_from_kernel_nofault(buffer, (void *)regs->ip - 6, MAX_INSN_SIZE)) + if (copy_from_kernel_nofault(buffer, (void *)addr - 6, MAX_INSN_SIZE)) return false; if (insn_decode_kernel(&insn, &buffer[offset])) return false; @@ -82,7 +82,7 @@ enum bug_trap_type handle_cfi_failure(struct pt_regs *regs) return BUG_TRAP_TYPE_NONE; } - if (!decode_cfi_insn(regs, &target, &type)) + if (!decode_cfi_insn(regs, addr, &target, &type)) return report_cfi_failure_noaddr(regs, addr); break; ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 2/3] x86/kcfi: Emit the FineIBT paranoid "cs" prefix as a byte 2026-10-12 9:04 [PATCH 0/3] x86/cfi: Fix a few kCFI issues found with GCC Kees Cook 2026-10-12 9:04 ` [PATCH 1/3] x86/kcfi: Decode the kCFI check from the trap address Kees Cook @ 2026-10-12 9:04 ` Kees Cook 2026-10-12 9:16 ` Peter Zijlstra 2026-10-12 9:59 ` [tip: x86/core] " tip-bot2 for Kees Cook 2026-10-12 9:04 ` [PATCH 3/3] objtool: Skip jump table jumps in the kCFI indirect call check Kees Cook 2 siblings, 2 replies; 10+ messages in thread From: Kees Cook @ 2026-10-12 9:04 UTC (permalink / raw) To: Peter Zijlstra Cc: Kees Cook, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin, Sami Tolvanen, Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt, x86, llvm, linux-kernel, linux-hardening The "cs" prefix on the LEA in the FineIBT paranoid caller template is padding: it places the LEA's 0xf0 immediate byte where it doubles as the LOCK prefix that makes the failing Jcc raise #UD. GNU as warns about it in every CONFIG_FINEIBT=y build: Warning: segment override on `lea' is ineffectual Clang's integrated assembler does not warn, and both assemble the same bytes. Emit the prefix with ".byte 0x2e" to silence GNU as. Build tested ARCH=x86_64 defconfig with CONFIG_CFI=y, with GCC 17.0.0 (experimental, with the kCFI series) and GNU as 2.47, and with Clang 24.0.0git: GNU as no longer warns, and the template assembles to the same bytes as before with both. Under QEMU with cfi=fineibt,paranoid, the paranoid caller check catches LKDTM's CFI_FORWARD_PROTO with both. Assisted-by: LLM Signed-off-by: Kees Cook <kees@kernel.org> --- arch/x86/kernel/alternative.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 91b1cdd16569..1300ca50e770 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -1448,7 +1448,8 @@ asm( ".pushsection .rodata \n" "fineibt_paranoid_start: \n" " mov $0x12345678, %eax \n" " cmpl -11(%r11), %eax \n" - " cs lea -0x10(%r11), %r11 \n" + " .byte 0x2e \n" + " lea -0x10(%r11), %r11 \n" "#fineibt_caller_size: \n" " jne fineibt_paranoid_start+0xd \n" "fineibt_paranoid_ind: \n" -- 2.55.0 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/3] x86/kcfi: Emit the FineIBT paranoid "cs" prefix as a byte 2026-10-12 9:04 ` [PATCH 2/3] x86/kcfi: Emit the FineIBT paranoid "cs" prefix as a byte Kees Cook @ 2026-10-12 9:16 ` Peter Zijlstra 2026-10-12 19:05 ` Andrew Cooper 2026-10-12 9:59 ` [tip: x86/core] " tip-bot2 for Kees Cook 1 sibling, 1 reply; 10+ messages in thread From: Peter Zijlstra @ 2026-10-12 9:16 UTC (permalink / raw) To: Kees Cook Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin, Sami Tolvanen, Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt, x86, llvm, linux-kernel, linux-hardening On Mon, Oct 12, 2026 at 02:04:25AM -0700, Kees Cook wrote: > The "cs" prefix on the LEA in the FineIBT paranoid caller template is > padding: it places the LEA's 0xf0 immediate byte where it doubles as the > LOCK prefix that makes the failing Jcc raise #UD. GNU as warns about it > in every CONFIG_FINEIBT=y build: > > Warning: segment override on `lea' is ineffectual Shees... ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/3] x86/kcfi: Emit the FineIBT paranoid "cs" prefix as a byte 2026-10-12 9:16 ` Peter Zijlstra @ 2026-10-12 19:05 ` Andrew Cooper 0 siblings, 0 replies; 10+ messages in thread From: Andrew Cooper @ 2026-10-12 19:05 UTC (permalink / raw) To: peterz, kees Cc: Andrew Cooper, bp, dave.hansen, hpa, justinstitt, linux-hardening, linux-kernel, llvm, mingo, morbo, nathan, ndesaulniers, samitolvanen, tglx, x86 > On Mon, Oct 12, 2026 at 02:04:25AM -0700, Kees Cook wrote: >> The "cs" prefix on the LEA in the FineIBT paranoid caller template is >> padding: it places the LEA's 0xf0 immediate byte where it doubles as the >> LOCK prefix that makes the failing Jcc raise #UD. GNU as warns about it >> in every CONFIG_FINEIBT=y build: >> >> Warning: segment override on `lea' is ineffectual > Shees... This is a binutils bug. Can't we fix it here? The claim in the warning is simply not true. This is an example where it absolutely does matter, and it also matters for legibility that we can avoid writing raw hex. ~Andrew ^ permalink raw reply [flat|nested] 10+ messages in thread
* [tip: x86/core] x86/kcfi: Emit the FineIBT paranoid "cs" prefix as a byte 2026-10-12 9:04 ` [PATCH 2/3] x86/kcfi: Emit the FineIBT paranoid "cs" prefix as a byte Kees Cook 2026-10-12 9:16 ` Peter Zijlstra @ 2026-10-12 9:59 ` tip-bot2 for Kees Cook 1 sibling, 0 replies; 10+ messages in thread From: tip-bot2 for Kees Cook @ 2026-10-12 9:59 UTC (permalink / raw) To: linux-tip-commits; +Cc: Kees Cook, Peter Zijlstra (Intel), x86, linux-kernel The following commit has been merged into the x86/core branch of tip: Commit-ID: 41d1119e2f8577b4bd01d31321c6761af9140ce7 Gitweb: https://git.kernel.org/tip/41d1119e2f8577b4bd01d31321c6761af9140ce7 Author: Kees Cook <kees@kernel.org> AuthorDate: Mon, 12 Oct 2026 02:04:25 -07:00 Committer: Peter Zijlstra <peterz@infradead.org> CommitterDate: Mon, 12 Oct 2026 11:47:35 +02:00 x86/kcfi: Emit the FineIBT paranoid "cs" prefix as a byte The "cs" prefix on the LEA in the FineIBT paranoid caller template is padding: it places the LEA's 0xf0 immediate byte where it doubles as the LOCK prefix that makes the failing Jcc raise #UD. GNU as warns about it in every CONFIG_FINEIBT=y build: Warning: segment override on `lea' is ineffectual Clang's integrated assembler does not warn, and both assemble the same bytes. Emit the prefix with ".byte 0x2e" to silence GNU as. Build tested ARCH=x86_64 defconfig with CONFIG_CFI=y, with GCC 17.0.0 (experimental, with the kCFI series) and GNU as 2.47, and with Clang 24.0.0git: GNU as no longer warns, and the template assembles to the same bytes as before with both. Under QEMU with cfi=fineibt,paranoid, the paranoid caller check catches LKDTM's CFI_FORWARD_PROTO with both. Assisted-by: LLM Signed-off-by: Kees Cook <kees@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/20261012090436.1676525-2-kees@kernel.org --- arch/x86/kernel/alternative.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 582c6d8..efbc11f 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -1455,7 +1455,8 @@ asm( ".pushsection .rodata \n" "fineibt_paranoid_start: \n" " mov $0x12345678, %eax \n" " cmpl -11(%r11), %eax \n" - " cs lea -0x10(%r11), %r11 \n" + " .byte 0x2e \n" + " lea -0x10(%r11), %r11 \n" "#fineibt_caller_size: \n" " jne fineibt_paranoid_start+0xd \n" "fineibt_paranoid_ind: \n" ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 3/3] objtool: Skip jump table jumps in the kCFI indirect call check 2026-10-12 9:04 [PATCH 0/3] x86/cfi: Fix a few kCFI issues found with GCC Kees Cook 2026-10-12 9:04 ` [PATCH 1/3] x86/kcfi: Decode the kCFI check from the trap address Kees Cook 2026-10-12 9:04 ` [PATCH 2/3] x86/kcfi: Emit the FineIBT paranoid "cs" prefix as a byte Kees Cook @ 2026-10-12 9:04 ` Kees Cook 2026-10-12 9:22 ` Peter Zijlstra 2 siblings, 1 reply; 10+ messages in thread From: Kees Cook @ 2026-10-12 9:04 UTC (permalink / raw) To: Peter Zijlstra Cc: Kees Cook, Josh Poimboeuf, Sami Tolvanen, Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt, llvm, linux-kernel, linux-hardening With MITIGATION_RETPOLINE=y, GCC lowers the computed goto in ___bpf_prog_run() to a jump through __x86_indirect_thunk_rdx. objtool puts that jump on the retpoline call list along with the indirect calls, so with CONFIG_CFI=y the kCFI check wants a UD2 before it: vmlinux.o: warning: objtool: ___bpf_prog_run+0x1e: no-cfi indirect call! The jump goes through the "jumptable" array, which objtool already reads from .data.rel.ro.c_jump_table, so its targets stay inside the function and need no kCFI check. Skip jump table jumps in the check. Clang does not emit this jump: with retpolines, it lowers the computed goto without an indirect jump. Build tested ARCH=x86_64 defconfig with CONFIG_LKDTM=y and CONFIG_CFI=y, with GCC 17.0.0 (experimental, with the kCFI series). Assisted-by: LLM Signed-off-by: Kees Cook <kees@kernel.org> --- tools/objtool/check.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 464f6c9d9ff0..d35c5305075f 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -4199,6 +4199,14 @@ static int validate_retpoline(struct objtool_file *file) list_for_each_entry(insn, &file->retpoline_call_list, call_node) { struct symbol *sym = insn_sym(insn); + /* + * A jump through a jump table stays inside the function, so + * it has no kCFI check. GCC turns the computed goto in + * ___bpf_prog_run() into one under MITIGATION_RETPOLINE. + */ + if (is_jump_table_jump(insn)) + continue; + if (sym && (is_notype_sym(sym) || is_func_sym(sym)) && !sym->nocfi) { struct instruction *prev = -- 2.55.0 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] objtool: Skip jump table jumps in the kCFI indirect call check 2026-10-12 9:04 ` [PATCH 3/3] objtool: Skip jump table jumps in the kCFI indirect call check Kees Cook @ 2026-10-12 9:22 ` Peter Zijlstra 2026-10-12 18:41 ` Kees Cook 0 siblings, 1 reply; 10+ messages in thread From: Peter Zijlstra @ 2026-10-12 9:22 UTC (permalink / raw) To: Kees Cook Cc: Josh Poimboeuf, Sami Tolvanen, Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt, llvm, linux-kernel, linux-hardening On Mon, Oct 12, 2026 at 02:04:26AM -0700, Kees Cook wrote: > With MITIGATION_RETPOLINE=y, GCC lowers the computed goto in > ___bpf_prog_run() to a jump through __x86_indirect_thunk_rdx. objtool > puts that jump on the retpoline call list along with the indirect calls, > so with CONFIG_CFI=y the kCFI check wants a UD2 before it: > > vmlinux.o: warning: objtool: ___bpf_prog_run+0x1e: no-cfi indirect call! > > The jump goes through the "jumptable" array, which objtool already reads > from .data.rel.ro.c_jump_table, so its targets stay inside the function > and need no kCFI check. Skip jump table jumps in the check. Clang does > not emit this jump: with retpolines, it lowers the computed goto without > an indirect jump. I am confused.. I don't see a computed goto in __bpf_prog_run(), and we build with -fno-jump-tables. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] objtool: Skip jump table jumps in the kCFI indirect call check 2026-10-12 9:22 ` Peter Zijlstra @ 2026-10-12 18:41 ` Kees Cook 0 siblings, 0 replies; 10+ messages in thread From: Kees Cook @ 2026-10-12 18:41 UTC (permalink / raw) To: Peter Zijlstra Cc: Josh Poimboeuf, Sami Tolvanen, Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt, llvm, linux-kernel, linux-hardening On Mon, Oct 12, 2026 at 11:22:50AM +0200, Peter Zijlstra wrote: > I am confused.. I don't see a computed goto in __bpf_prog_run(), and we > build with -fno-jump-tables. It's the interpreter, ___bpf_prog_run() (three underscores) in kernel/bpf/core.c, not the __bpf_prog_run() wrapper in filter.h: static const void * const jumptable[256] __annotate_jump_table = { [0 ... 255] = &&default_label, ... }; ... select_insn: goto *jumptable[insn->code]; So it's a manually constructed jump table, not the "normal" table-from-switch stuff that -fno-jump-tables suppresses (though see below about Clang). objtool already knows about it, with annotations added back in 2019 in commit e55a73251da33 ("bpf: Fix ORC unwinding in non-JIT BPF code"). With retpolines, GCC emits a single dispatch that every handler uses: movzbl (%rbx),%esi movzbl %sil,%edx mov jumptable(,%rdx,8),%rdx jmp __x86_indirect_thunk_rdx Clang never has this jump: with retpolines, LLVM's IndirectBrExpand pass turns the label addresses into indexes and the "goto *" into a switch, which Clang's -fno-jump-tables then makes a compare tree. So it's only constructed this way under GCC, but since now we can turn on kCFI with GCC, the objtool warning about indirects without kcfi protection trips. -- Kees Cook ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-10-12 19:05 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-10-12 9:04 [PATCH 0/3] x86/cfi: Fix a few kCFI issues found with GCC Kees Cook 2026-10-12 9:04 ` [PATCH 1/3] x86/kcfi: Decode the kCFI check from the trap address Kees Cook 2026-10-12 9:59 ` [tip: x86/urgent] " tip-bot2 for Kees Cook 2026-10-12 9:04 ` [PATCH 2/3] x86/kcfi: Emit the FineIBT paranoid "cs" prefix as a byte Kees Cook 2026-10-12 9:16 ` Peter Zijlstra 2026-10-12 19:05 ` Andrew Cooper 2026-10-12 9:59 ` [tip: x86/core] " tip-bot2 for Kees Cook 2026-10-12 9:04 ` [PATCH 3/3] objtool: Skip jump table jumps in the kCFI indirect call check Kees Cook 2026-10-12 9:22 ` Peter Zijlstra 2026-10-12 18:41 ` Kees Cook
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®