On Mon, Aug 10, 2026 at 11:31:10AM +0100, Will Deacon wrote:
> On Fri, Aug 07, 2026 at 02:46:11PM -0700, Josh Poimboeuf wrote:
> > The following BTI exception was seen when loading a livepatch module:
> >
> > Internal error: Oops - BTI: 0000000036000001 [#1] SMP
> > pstate: 634004c9 (nZCv daIF +PAN -UAO +TCO +DIT -SSBS BTYPE=jc)
> > pc : kill_orphaned_pgrp+0x0/0x150
> > lr : do_exit+0x498/0xaf0 [livepatch_combined]
> >
> > The problem is that the patch module's do_exit() is branching to a
> > static function in vmlinux using a module PLT veneer (indirect branch),
> > but the target function doesn't have a BTI landing pad.
> >
> > Clang 21+ omits the landing pad for static functions which can only be
> > reached by a direct branch. That's fine for ordinary modules which only
> > branch to global exported functions. But livepatch modules use klp
> > relocations to reference arbitrary kernel symbols, and with
> > CONFIG_RANDOMIZE_MODULE_REGION_FULL the module is far enough from the
> > kernel that every R_AARCH64_CALL26 needs a PLT.
> >
> > RET is exempt from BTI checking, so use it instead of BR when the target
> > has no landing pad, similar to what ftrace and BPF do.
>
> Hmm, doesn't that somewhat undermine the purpose of using BTI in the
> kernel? Now we're going to create PLTs that can branch to arbitrary
> addresses.
Yes, but just to clarify:
- Only with livepatch modules loaded (and we can add an
is_livepatch_module() check).
- Only a small minority of livepatch klp relocations need it.
- There are already other instances of "ret <reg>" in the kernel in
ftrace, BPF, and kvm.
> > This was found by testing with klp-build and Clang 21, but the issue is
> > not specific to klp-build. It's inherent to any livepatch module use of
> > klp relocations.
> >
> > Previous tests with Clang 20 did not show this problem, as older Clang
> > unconditionally emits "bti c" for every C function.
>
> Is there an option to restore that behaviour if CONFIG_LIVEPATCH=y?
> Otherwise, I think I'd be more inclined to add yet-another dependency
> to CONFIG_ARM64_BTI_KERNEL so it's disabled if LIVEPATCH is selected.
Hm, looking deeper, is BTI just fundamentally broken now, independent of
livepatch?
config ARM64_BTI_KERNEL
...
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106671
depends on !CC_IS_GCC
...
AFAICT, the reason for the "depends on !CC_IS_GCC" is that GCC was
already doing the exact same thing Clang is now doing: namely, omitting
BTI for static functions that don't have a pointer taken to them.
So Clang 21+ now has the original GCC edge case: an .init.text direct
branching to a .text function which happens to be allocated >= 128MB
away and which doesn't have BTI.
In which case I think to properly support BTI going forward we would
need two "veneers"? Either that or remove BTI kernel support
altogether.
--
Josh