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

Reply via email to