On a kernel whose text exceeds the +/128MB direct branch range, the
linker inserts veneers.  With BTI enabled, the veneers' indirect branch
targets need a BTI landing pad, which not all functions have starting
with Clang 21 (and for all versions of GCC).

In such cases the linker can emit a second veneer close to the target
which has the landing pad along with a direct branch to the target.
However, that's currently not being done, so GCC and Clang 21+ are
broken with BTI on large kernels.

Only newer linkers have proper support for adding the second veneer,
starting with binutils 2.42 and LLVM 20.

Only allow a large kernel with the right combination of compiler and
linker.

Signed-off-by: Josh Poimboeuf <[email protected]>
---
 arch/arm64/Kconfig              | 7 +++++++
 arch/arm64/kernel/vmlinux.lds.S | 5 +++++
 2 files changed, 12 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b3afe0688919b..2687b71438661 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2123,6 +2123,13 @@ config ARM64_BTI_KERNEL
          is enabled and the system supports BTI all kernel code including
          modular code must have BTI enabled.
 
+config CC_OMITS_BTI_LANDING_PADS
+       def_bool !CC_IS_CLANG || CLANG_VERSION >= 210000
+
+config LD_HAS_BTI_STUBS
+       def_bool (LD_IS_BFD && LD_VERSION >= 24200) || \
+                (LD_IS_LLD && LLD_VERSION >= 200000)
+
 config CC_HAS_BRANCH_PROT_PAC_RET_BTI
        # GCC 9 or later, clang 8 or later
        def_bool $(cc-option,-mbranch-protection=pac-ret+leaf+bti)
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index af1d720209764..3a88da9212831 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -414,6 +414,11 @@ ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) 
<= 3*PAGE_SIZE,
 #ifdef CONFIG_KVM
 ASSERT(__hyp_bss_start == __bss_start, "HYP and Host BSS are misaligned")
 #endif
+
+#if defined(CONFIG_ARM64_BTI_KERNEL) && !defined(CONFIG_COMPILE_TEST) && \
+    defined(CONFIG_CC_OMITS_BTI_LANDING_PADS) && 
!defined(CONFIG_LD_HAS_BTI_STUBS)
+ASSERT(__exittext_end - _text <= SZ_128M, "Kernel text too big for BTI")
+#endif
 /*
  * If padding is applied before .head.text, virt<->phys conversions will fail.
  */
-- 
2.55.0


Reply via email to