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]>

Reply via email to