[RFC 0/3] kbuild: modules: Fixup arm64 BTI relocations
Emanuele Rocca
emanuele.rocca at arm.com
Wed Oct 7 01:09:37 PDT 2026
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 <emanuele.rocca at arm.com>
More information about the linux-arm-kernel
mailing list