It was discovered in the Fedora Asahi room that the Linux kernel has been silently disabling in-kernel BTI since 6.0 because of a bug in GCC that results in the BTI instruction not being inserted for cross-section direct calls. This seriously limits BTI protection that was enabled in Fedora 33: https://fedoraproject.org/wiki/Changes/Aarch64_PointerAuthentication Reproducible: Always Actual Results: CONFIG_ARM64_BTI_KERNEL=y is missing in the installed kernel config file Expected Results: CONFIG_ARM64_BTI_KERNEL=y is found in the installed kernel config file Upstream GCC bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106671 Upstream Linux commit: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c0a454b9044fdc99486853aa424e5b3be2107078
I think Arm identified part of this as a binutils bug and fixed it? Bug 30076 - aarch64: stubs can add indirect branch that breaks BTI <https://sourceware.org/bugzilla/show_bug.cgi?id=30076> The remaining issue concerns kernel module loading, which is rather tricky because AArch64 does not have BTI-exempt branches (x86-64 has a NOTRACK prefix for that).
What's the problem with kernel module loading? The whole toolchain is controlled by Fedora, so modules can be built with BTI. As for proprietary ones, BTI can be disabled when such modules are loaded: it'll be a strict improvement over the current situation.
As far as I understand it, kernel modules cannot always use direct calls to exported symbols. If the module is loaded too far away from the kernel code, an indirect call has to be used. This means that the called function becomes an indirect branch target and needs a BTI marker. However, Arm does not want to add markers to all (exported?) kernel functions proactively, as explained on the GCC bug. (Note that kernel module loading is a dynamic linking mechanism, but it's very different from ELF dynamic linking we implement across binutils/gcc/glibc.)
This message is a reminder that Fedora Linux 40 is nearing its end of life. Fedora will stop maintaining and issuing updates for Fedora Linux 40 on 2025-05-13. It is Fedora's policy to close all bug reports from releases that are no longer maintained. At that time this bug will be closed as EOL if it remains open with a 'version' of '40'. Package Maintainer: If you wish for this bug to remain open because you plan to fix it in a currently maintained version, change the 'version' to a later Fedora Linux version. Note that the version field may be hidden. Click the "Show advanced fields" button if you do not see it. Thank you for reporting this issue and we are sorry that we were not able to fix it before Fedora Linux 40 is end of life. If you would still like to see this bug fixed and are able to reproduce it against a later version of Fedora Linux, you are encouraged to change the 'version' to a later version prior to this bug being closed.
Still an issue now, marked as such.
I duplicated this yesterday too on F43 + mainline kernel by enlarging a module. I think the sequence is pretty specific to the -fpatchable-function-entry + static functions + inner module cross sectional calls. All of which are totally grey area, and the problematic sequence is 'entry: nop; nop; paciasp; ...' because it expects to only be directly called from functions inside the compilation unit rather than 'entry: bti c; nop; nop; paciasp; ...' that shows up for global symbols. I understand there was an ABI update, so I need to check and see if it actually addresses this case, which is at least largely caused by the patchable-function-entry because without it the paciasp correctly acts as the landing pad, although I guess in theory this could trigger with just static leaf functions, that for whatever reason, aren't inlined. I'm trying (and at the moment failing) to recreate this with a standalone userspace compilation. OTOH, I also suspect that the kernel module loader+ftrace could be tweaked to detect it and simply correct the call address and disable the ftrace point, which is what happens for a lot of static functions anyway as they tend to get inlined. And to the earlier point about the BTI on fedora, this only affects the kernel's BTI usage, not the system as a whole where it remains in force.
As a FYI: The abi change: https://github.com/ARM-software/abi-aa/commit/0051acdaf08fdadaed5b206fb8977a65e53e59ba
And as a further clarification, the case I hit isn't for an exported symbol, its the __init entrypoint calling a static function within the module. So normally it would be just a direct bl to that function and doesn't need a landing pad, but because __init is in another section it needs a relocation... for a static function...
Since its been a while, I have a partial patch to the binutils/bfd code which detects this, and attempts to enable this with the stub/veneer. The idea is to add an additional 'force-veneer-for-cross-section' type command line option for partial -r ld links, which are used by the kernel for linking modules. This differs from how ld only inserts the veneers when finalized (shared or otherwise) based on the actual distance between the caller and the target function. In that case, ld actually does the right thing and goes ahead and inserts the bti landing pad and adjusts the caller's relocation. This can be simulated with a userspace executable by simply setting the offset for a section (in the linker script) far away from the text section being called and then doing the final link. So the last, and important missing piece above is that beyond the above requirements the final link must still be ET_REL to trigger this.