On 2026-10-06 05:18, Jeremy Linton wrote: > The kernel module loader, the arm64 ABI, GCC/Clang, and the static > linkers operate with slightly different assumptions about which > functions require BTI landing pads. > > A static function called only directly does not normally need a BTI > landing pad, so compilers omit it. A static linker producing an ET_REL > module treats R_AARCH64_CALL26 as a direct branch and leaves the > relocation for the module loader or later link pass. It does not know > the final distance between sections or whether the loader will later > require an indirect branch fixup. > > This matters when a caller and callee are placed in different sections, > for example by __init. The arm64 module loader may replace such a > CALL26 relocation with a fixup containing an indirect branch, making an > otherwise direct only function a BTI target. Ftrace makes this more > likely because its entry NOP can replace a PAC instruction that would > otherwise be a valid BTI landing pad. > > A linker could conservatively add veneers to affected cross section > calls, but that would require knowledge of arm64 module loader fixup > semantics and is not part of the generic relocatable link contract. > > Lets fix this by handling the module specific transformation during > the kernel build. Scan cross section calls and, when the target lacks > a BTI compatible landing pad, place a veneer in the target section, > redirect the relocation to the veneer, and branch directly from the > veneer to the original function entry. > > Jeremy Linton (3): > kbuild: modules: Add arm64 BTI fixup utility > kbuild: modules: Build and trigger BTI scanner for arm64 > arm64: bti: Drop compiler specific BTI checks
Tested as follows on BTI-capable hardware: - Built a kernel with these patches and CONFIG_ARM64_BTI_KERNEL=y - Verified that a test kernel module can successfully branch indirectly to a valid 'bti c' landing pad - The same test kernel module triggers an Oops - BTI if branching indirectly to a nop Internal error: Oops - BTI: 0000000036000002 [#1] SMP Modules linked in: bti_probe(OE+) binfmt_misc nls_iso8859_1 aes_ce_blk [...] [...] pc : bti_bad+0x1c/0x28 [bti_probe] lr : bti_bad+0x14/0x28 [bti_probe] sp : ffff800083933a40 x29: ffff800083933a40 x28: 000000000000000c x27: 0000000000000000 x26: 0000000000000000 x25: ffff800083933c90 x24: ffffaaa7c52c7058 x23: ffffaaa7567d1040 x22: 0000000000000000 x21: 0000000000000000 x20: ffff0000d11cd100 x19: 0000000000000001 x18: ffff800083795058 x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 x14: ffffffffffffffff x13: 7465677261742049 x12: 54422064696c6176 x11: 6e6920676e697265 x10: 0000000000000000 x9 : 0000000000000000 x8 : 0000000000000000 x7 : 0000000000000000 x6 : 0000000000000000 x5 : 0000000000000000 x4 : 0000000000000000 x3 : 0000000000000000 x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffffaaa7567cf044 Call trace: bti_bad+0x1c/0x28 [bti_probe] (P) bti_probe_init+0x78/0xff8 [bti_probe] No Oops was hit, as expected, booting the kernel with arm64.nobti. Other than that, the system works fine under regular workloads. Tested-By: Emanuele Rocca <[email protected]>

