* [RFC 0/3] kbuild: modules: Fixup arm64 BTI relocations
@ 2026-10-06 22:18 Jeremy Linton
2026-10-06 22:18 ` [RFC 1/3] kbuild: modules: Add arm64 BTI fixup utility Jeremy Linton
` (4 more replies)
0 siblings, 5 replies; 9+ messages in thread
From: Jeremy Linton @ 2026-10-06 22:18 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-kbuild, linux-modules, broonie, jpoimboe, nathan, nsc,
mcgrof, petr.pavlu, da.gomez, samitolvanen, atomlin, ndesaulniers,
mark.rutland, will, catalin.marinas, ardb, Emanuele.Rocca,
linux-kernel, Jeremy Linton
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
arch/arm64/Kconfig | 6 -
scripts/Makefile | 3 +
scripts/Makefile.modfinal | 12 +-
scripts/module-bti-check.c | 665 +++++++++++++++++++++++++++++++++++++
4 files changed, 679 insertions(+), 7 deletions(-)
create mode 100644 scripts/module-bti-check.c
--
2.55.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [RFC 1/3] kbuild: modules: Add arm64 BTI fixup utility
2026-10-06 22:18 [RFC 0/3] kbuild: modules: Fixup arm64 BTI relocations Jeremy Linton
@ 2026-10-06 22:18 ` Jeremy Linton
2026-10-06 22:32 ` sashiko-bot
2026-10-06 22:18 ` [RFC 2/3] kbuild: modules: Build and trigger BTI scanner for arm64 Jeremy Linton
` (3 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Jeremy Linton @ 2026-10-06 22:18 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-kbuild, linux-modules, broonie, jpoimboe, nathan, nsc,
mcgrof, petr.pavlu, da.gomez, samitolvanen, atomlin, ndesaulniers,
mark.rutland, will, catalin.marinas, ardb, Emanuele.Rocca,
linux-kernel, Jeremy Linton
The kernel module loader, the arm64 ABI, and GCC/Clang plus the static
linkers operate with slightly different assumptions about which
functions require BTI landing pads.
A static function called directly does not need a BTI landing pad, so
compilers omit it. Likewise, a static linker producing an ET_REL
module treats R_AARCH64_CALL26 as a direct branch and leaves the
relocation for the module loader. 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.
Handle the module specific transformation here instead. 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.
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
scripts/module-bti-check.c | 666 +++++++++++++++++++++++++++++++++++++
1 file changed, 666 insertions(+)
create mode 100644 scripts/module-bti-check.c
diff --git a/scripts/module-bti-check.c b/scripts/module-bti-check.c
new file mode 100644
index 000000000000..c8bef0ed90bb
--- /dev/null
+++ b/scripts/module-bti-check.c
@@ -0,0 +1,666 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Fix cross section AArch64 calls whose targets lack BTI landing pads.
+ *
+ * This utility scans for R_ARCH64_CALL26 cross section calls whose targets
+ * lack a BTI compatible landing pad. It places a veneer in the target
+ * function's section, redirects the relocation to the veneer, and uses a
+ * direct branch from the veneer to the original function entry point.
+ *
+ * This can't fix text sections where the target is more than 128M away.
+ * The scanner detects those cases and fails. Making the target non static
+ * causes the compiler to emit a suitable landing pad.
+ */
+
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <getopt.h>
+#include <libelf.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tools/be_byteshift.h>
+#include <tools/le_byteshift.h>
+
+#define BTI_MASK 0xffffff3f
+#define BTI_INSN 0xd503241f
+#define BTI_C_INSN 0xd503245f
+#define PACIASP_INSN 0xd503233f
+#define PACIBSP_INSN 0xd503237f
+#define B_INSN 0x14000000
+#define VENEER_SIZE 8 /* Two instructions, BTI C, B Original */
+
+struct object {
+ const char *name;
+ Elf *elf;
+ Elf_Data *symdata;
+ Elf_Data *xndxdata;
+ GElf_Shdr symshdr;
+ size_t shnum;
+ size_t shstrndx;
+ bool changed;
+};
+
+struct function {
+ const char *name;
+ uint64_t value;
+ unsigned int section_index;
+};
+
+struct location {
+ uint64_t value;
+ uint32_t branch;
+ unsigned int section_index;
+ unsigned int secsym;
+};
+
+struct veneer {
+ struct veneer *next;
+ uint64_t target;
+ uint64_t value;
+ unsigned int section_index;
+ unsigned int secsym;
+ uint32_t insns[VENEER_SIZE / sizeof(uint32_t)];
+};
+
+static int elf_error(const struct object *obj)
+{
+ fprintf(stderr, "%s: %s\n", obj->name, elf_errmsg(-1));
+
+ return -ELIBBAD;
+}
+
+static bool get_sym(const struct object *obj, size_t ndx, GElf_Sym *sym,
+ unsigned int *section_index)
+{
+ Elf32_Word xndx;
+
+ if (!gelf_getsymshndx(obj->symdata, obj->xndxdata, ndx, sym, &xndx))
+ return false;
+
+ *section_index = sym->st_shndx == SHN_XINDEX ? xndx : sym->st_shndx;
+
+ return true;
+}
+
+static const char *section_name(const struct object *obj, unsigned int ndx)
+{
+ GElf_Shdr shdr;
+ Elf_Scn *scn;
+ const char *name = NULL;
+
+ scn = elf_getscn(obj->elf, ndx);
+ if (!scn)
+ goto out;
+
+ if (!gelf_getshdr(scn, &shdr))
+ goto out;
+
+ name = elf_strptr(obj->elf, obj->shstrndx, shdr.sh_name);
+
+out:
+ return name ? name : "<invalid>";
+}
+
+static const char *symbol_name(const struct object *obj, const GElf_Sym *sym)
+{
+ const char *name;
+
+ name = elf_strptr(obj->elf, obj->symshdr.sh_link, sym->st_name);
+
+ return name ? name : "<invalid>";
+}
+
+static int init_object(struct object *obj)
+{
+ GElf_Ehdr ehdr;
+ size_t symtab = 0;
+ size_t i;
+
+ if (elf_kind(obj->elf) != ELF_K_ELF)
+ return -ENOEXEC;
+
+ if (gelf_getclass(obj->elf) != ELFCLASS64)
+ return -ENOEXEC;
+
+ if (!gelf_getehdr(obj->elf, &ehdr))
+ goto out;
+
+ if (elf_getshdrnum(obj->elf, &obj->shnum) < 0)
+ goto out;
+
+ if (elf_getshdrstrndx(obj->elf, &obj->shstrndx) < 0)
+ goto out;
+
+ if (ehdr.e_type != ET_REL || ehdr.e_machine != EM_AARCH64)
+ return -ENOEXEC;
+
+ for (i = 1; i < obj->shnum; i++) {
+ Elf_Scn *scn;
+ GElf_Shdr shdr;
+
+ scn = elf_getscn(obj->elf, i);
+ if (!scn)
+ goto out;
+
+ if (!gelf_getshdr(scn, &shdr))
+ goto out;
+
+ if (shdr.sh_type != SHT_SYMTAB)
+ continue;
+
+ if (symtab)
+ return -ENOEXEC;
+
+ symtab = i;
+ obj->symshdr = shdr;
+ obj->symdata = elf_getdata(scn, NULL);
+ if (!obj->symdata)
+ goto out;
+ }
+
+ if (!symtab || !obj->symshdr.sh_entsize ||
+ obj->symshdr.sh_size % obj->symshdr.sh_entsize)
+ return -ENOEXEC;
+
+ for (i = 1; i < obj->shnum; i++) {
+ Elf_Scn *scn;
+ GElf_Shdr shdr;
+
+ scn = elf_getscn(obj->elf, i);
+ if (!scn)
+ goto out;
+
+ if (!gelf_getshdr(scn, &shdr))
+ goto out;
+
+ if (shdr.sh_type == SHT_SYMTAB_SHNDX && shdr.sh_link == symtab) {
+ /* duplicate SHT_SYMTAB_SHNDX?! */
+ if (obj->xndxdata)
+ return -ENOEXEC;
+
+ obj->xndxdata = elf_getdata(scn, NULL);
+ if (!obj->xndxdata)
+ goto out;
+ }
+ }
+
+ return 0;
+out:
+ return elf_error(obj);
+}
+
+static bool executable_section(const struct object *obj, unsigned int ndx)
+{
+ GElf_Shdr shdr;
+ Elf_Scn *scn = elf_getscn(obj->elf, ndx);
+
+ if (ndx == SHN_UNDEF || !scn)
+ return false;
+
+ return gelf_getshdr(scn, &shdr) && (shdr.sh_flags & SHF_EXECINSTR);
+}
+
+static int get_first_insn(const struct object *obj, const struct function *func,
+ uint32_t *insn)
+{
+ Elf_Scn *scn;
+ Elf_Data *data;
+ const void *p;
+
+ scn = elf_getscn(obj->elf, func->section_index);
+ if (!scn)
+ return -ENOEXEC;
+
+ data = elf_getdata(scn, NULL);
+ if (!data)
+ return -ENOEXEC;
+
+ if (func->value > data->d_size ||
+ sizeof(*insn) > data->d_size - func->value)
+ return -ENOEXEC;
+
+ p = (char *)data->d_buf + func->value;
+ *insn = get_unaligned_le32(p);
+ return 0;
+}
+
+static void put_insn(void *p, uint32_t insn)
+{
+ put_unaligned_le32(insn, p);
+}
+
+/* Is the target instruction a valid BTI landing pad? */
+static bool is_landing_pad(uint32_t insn)
+{
+ return (insn & BTI_MASK) == BTI_INSN || insn == PACIASP_INSN ||
+ insn == PACIBSP_INSN;
+}
+
+static bool find_function(const struct object *obj, unsigned int section_index,
+ uint64_t value, bool exact, struct function *func)
+{
+ size_t count = obj->symshdr.sh_size / obj->symshdr.sh_entsize, i;
+ bool found = false;
+
+ for (i = 0; i < count; i++) {
+ GElf_Sym sym;
+ unsigned int symsec;
+
+ if (!get_sym(obj, i, &sym, &symsec))
+ continue;
+
+ if (symsec != section_index)
+ continue;
+
+ if (GELF_ST_TYPE(sym.st_info) != STT_FUNC)
+ continue;
+
+ if (value < sym.st_value)
+ continue;
+
+ if (exact && sym.st_value != value)
+ continue;
+
+ if (!exact && sym.st_size && value - sym.st_value >= sym.st_size)
+ continue;
+
+ if (found && sym.st_value < func->value)
+ continue;
+
+ func->name = symbol_name(obj, &sym);
+ func->value = sym.st_value;
+ func->section_index = section_index;
+ found = true;
+ }
+ return found;
+}
+
+/*
+ * Resolve the relocation target as a section-relative offset.
+ * Treat invalid targets as unresolved.
+ */
+static bool relocation_target(const struct object *obj, const GElf_Rela *rela,
+ struct function *func)
+{
+ GElf_Sym sym;
+ unsigned int section_index;
+ uint64_t value;
+
+ if (!get_sym(obj, GELF_R_SYM(rela->r_info), &sym, §ion_index))
+ return false;
+
+ if (!executable_section(obj, section_index))
+ return false;
+
+ /* CALL26 relocates to symbol + addend */
+ if (rela->r_addend >= 0) {
+ if (sym.st_value > UINT64_MAX - (uint64_t)rela->r_addend)
+ return false;
+ value = sym.st_value + rela->r_addend;
+ } else {
+ uint64_t magnitude = (uint64_t)(-(rela->r_addend + 1)) + 1;
+
+ if (sym.st_value < magnitude)
+ return false;
+ value = sym.st_value - magnitude;
+ }
+
+ if (!find_function(obj, section_index, value, false, func))
+ func->name = symbol_name(obj, &sym);
+
+ func->value = value;
+ func->section_index = section_index;
+
+ return true;
+}
+
+static bool encode_branch(uint64_t from, uint64_t target, uint32_t *insn_position)
+{
+ int64_t delta;
+
+ if ((from | target) & 3)
+ return false;
+
+ delta = (int64_t)(target - from);
+
+ if (delta < -(1LL << 27) || delta >= (1LL << 27))
+ return false;
+
+ *insn_position = B_INSN | ((delta >> 2) & 0x03ffffff);
+ return true;
+}
+
+static int find_possible_location(const struct object *obj,
+ const struct function *target, struct location *loc)
+{
+ size_t count = obj->symshdr.sh_size / obj->symshdr.sh_entsize, i;
+ GElf_Shdr shdr;
+ Elf_Scn *scn = elf_getscn(obj->elf, target->section_index);
+
+ /* Keep the veneer and direct branch in the callee's section. */
+ if (!scn || !gelf_getshdr(scn, &shdr) || shdr.sh_type != SHT_PROGBITS ||
+ (shdr.sh_size & 3) || shdr.sh_size > UINT64_MAX - VENEER_SIZE)
+ return -EINVAL;
+
+ for (i = 0; i < count; i++) {
+ GElf_Sym sym;
+ unsigned int section_index;
+
+ if (get_sym(obj, i, &sym, §ion_index)
+ && section_index == target->section_index
+ && GELF_ST_TYPE(sym.st_info) == STT_SECTION)
+ break;
+ }
+
+ if (i == count)
+ return 1;
+
+ loc->value = shdr.sh_size;
+ loc->section_index = target->section_index;
+ loc->secsym = i;
+
+ if (!encode_branch(loc->value + VENEER_SIZE - 4, target->value,
+ &loc->branch))
+ return 1;
+
+ return 0;
+}
+
+static int insert_veneer(struct object *obj, const struct location *loc,
+ uint64_t target, struct veneer **result)
+{
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Shdr shdr;
+ struct veneer *veneer;
+
+ veneer = calloc(1, sizeof(*veneer));
+ if (!veneer)
+ return -ENOMEM;
+
+ veneer->target = target;
+ veneer->value = loc->value;
+ veneer->section_index = loc->section_index;
+ veneer->secsym = loc->secsym;
+
+ put_insn(&veneer->insns[0], BTI_C_INSN);
+ put_insn(&veneer->insns[1], loc->branch);
+
+ scn = elf_getscn(obj->elf, loc->section_index);
+ if (!scn || !gelf_getshdr(scn, &shdr))
+ goto out;
+
+ data = elf_newdata(scn);
+ if (!data)
+ goto out;
+
+ /* Libelf references this buffer until elf_end(), so the veneer owns it. */
+ data->d_buf = veneer->insns;
+ data->d_type = ELF_T_BYTE;
+ data->d_size = VENEER_SIZE;
+ data->d_align = 4;
+ data->d_version = EV_CURRENT;
+ shdr.sh_size += VENEER_SIZE;
+
+ if (!gelf_update_shdr(scn, &shdr)) {
+ data->d_buf = NULL;
+ goto out;
+ }
+
+ obj->changed = true;
+ *result = veneer;
+
+ return 0;
+out:
+ free(veneer);
+ return elf_error(obj);
+}
+
+static int get_veneer(struct object *obj, struct veneer **veneers,
+ const struct function *target, struct veneer **result)
+{
+ struct veneer *veneer;
+ struct location loc;
+ int ret = EXIT_SUCCESS;
+
+ for (veneer = *veneers; veneer; veneer = veneer->next) {
+ if (veneer->section_index == target->section_index &&
+ veneer->target == target->value) {
+ *result = veneer;
+ goto out;
+ }
+ }
+
+ /* no existing veneer found, create one */
+ ret = find_possible_location(obj, target, &loc);
+ if (ret) {
+ fprintf(stderr, "%s: cannot place BTI veneer for %s\n",
+ obj->name, target->name);
+ goto out;
+ }
+
+ ret = insert_veneer(obj, &loc, target->value, &veneer);
+ if (ret)
+ goto out;
+
+ veneer->next = *veneers;
+ *veneers = veneer;
+
+ *result = veneer;
+
+ fprintf(stderr, "%s: grew %s for BTI veneer to %s at +0x%llx; "
+ "B-to-target distance is %lld bytes\n", obj->name,
+ section_name(obj, target->section_index), target->name,
+ (unsigned long long)loc.value,
+ (long long)(target->value - (loc.value + 4)));
+
+out:
+ return ret;
+}
+
+static int scan_relocations(struct object *obj, struct veneer **veneers, bool fix)
+{
+ size_t i;
+ int unfixed = 0;
+ int ret = EXIT_SUCCESS;
+
+ for (i = 1; i < obj->shnum; i++) {
+ Elf_Scn *scn = elf_getscn(obj->elf, i);
+ Elf_Data *data;
+ GElf_Shdr shdr;
+ size_t j, count;
+
+ if (!scn || !gelf_getshdr(scn, &shdr))
+ goto out_elferr;
+
+ if (shdr.sh_type != SHT_RELA || !executable_section(obj, shdr.sh_info))
+ continue;
+
+ data = elf_getdata(scn, NULL);
+ if (!data || !shdr.sh_entsize || shdr.sh_size % shdr.sh_entsize) {
+ ret = -ENOEXEC;
+ goto out;
+ }
+
+ count = shdr.sh_size / shdr.sh_entsize;
+ for (j = 0; j < count; j++) {
+ GElf_Rela rela;
+ struct function target, caller;
+ struct veneer *veneer;
+ const char *source;
+ uint32_t insn;
+
+ if (!gelf_getrela(data, j, &rela))
+ goto out_elferr;
+
+ if (GELF_R_TYPE(rela.r_info) != R_AARCH64_CALL26)
+ continue;
+
+ if (!relocation_target(obj, &rela, &target))
+ continue;
+
+ if (target.section_index == shdr.sh_info)
+ continue;
+
+ ret = get_first_insn(obj, &target, &insn);
+ if (ret)
+ goto out;
+
+ if (is_landing_pad(insn))
+ continue;
+
+ if (find_function(obj, shdr.sh_info, rela.r_offset,
+ false, &caller))
+ source = caller.name;
+ else
+ source = "<unknown>";
+
+ if (fix) {
+ ret = get_veneer(obj, veneers, &target, &veneer);
+ if (ret)
+ goto out;
+
+ rela.r_info = GELF_R_INFO(veneer->secsym, R_AARCH64_CALL26);
+ rela.r_addend = veneer->value;
+ if (!gelf_update_rela(data, j, &rela))
+ return elf_error(obj);
+
+ obj->changed = true;
+ continue;
+ }
+
+ fprintf(stderr,
+ "%s: cross-section call from %s%s%s+0x%llx to %s (%s+0x%llx) lacks a BTI landing pad\n",
+ obj->name, source ?: "", source ? " " : "",
+ section_name(obj, shdr.sh_info),
+ (unsigned long long)rela.r_offset, target.name,
+ section_name(obj, target.section_index),
+ (unsigned long long)target.value);
+
+ unfixed++;
+ }
+ }
+
+ ret = unfixed;
+out:
+ return ret;
+out_elferr:
+ return elf_error(obj);
+}
+
+static int process_file(const char *name, bool fix)
+{
+ struct object obj = { .name = name };
+ struct veneer *veneers = NULL;
+ int fd = -1, ret;
+
+
+ fd = open(name, fix ? O_RDWR : O_RDONLY);
+ if (fd < 0) {
+ ret = -errno;
+ goto out;
+ }
+
+ obj.elf = elf_begin(fd, fix ? ELF_C_RDWR : ELF_C_READ, NULL);
+ if (!obj.elf) {
+ fprintf(stderr, "%s: %s\n", name, elf_errmsg(-1));
+ ret = -ELIBBAD;
+ goto out;
+ }
+
+ ret = init_object(&obj);
+ if (ret)
+ goto out;
+
+ ret = scan_relocations(&obj, &veneers, fix);
+ if (!ret && fix && obj.changed) {
+ if (elf_update(obj.elf, ELF_C_WRITE) < 0)
+ ret = elf_error(&obj);
+ }
+
+
+out:
+ if (obj.elf) {
+ if (elf_end(obj.elf) < 0) {
+ fprintf(stderr, "%s: %s\n", name, elf_errmsg(-1));
+ ret = -ELIBBAD;
+ }
+ }
+
+ /* Must happen after elf end, to assure correctness */
+ while (veneers) {
+ struct veneer *next = veneers->next;
+
+ free(veneers);
+ veneers = next;
+ }
+
+ if (fd >= 0)
+ close(fd);
+
+
+ if (ret < 0) {
+ if (ret != -ELIBBAD)
+ fprintf(stderr, "%s: %s\n", name, strerror(-ret));
+ return EXIT_FAILURE;
+ }
+
+ return ret;
+}
+
+
+int main(int argc, char **argv)
+{
+ bool warn = false;
+ bool fix = false;
+ int option, i, ret = EXIT_FAILURE;
+
+ static const struct option options[] = {
+ { "fix", no_argument, NULL, 'f' },
+ { "warn", no_argument, NULL, 'w' },
+ { }
+ };
+
+ while ((option = getopt_long(argc, argv, "", options, NULL)) != -1) {
+ switch (option) {
+ case 'f':
+ fix = true;
+ break;
+ case 'w':
+ warn = true;
+ break;
+ default:
+ goto out;
+ }
+ }
+ if (optind == argc) {
+ fprintf(stderr, "Usage: %s [--fix] [--warn] <module.ko>...\n",
+ argv[0]);
+ goto out;
+ }
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ fprintf(stderr, "libelf initialization failed: %s\n", elf_errmsg(-1));
+ goto out;
+ }
+
+ for (i = optind; i < argc; i++) {
+ int status = process_file(argv[i], fix);
+
+ if (status && !warn) {
+ ret = status;
+ goto out;
+ }
+ }
+
+ ret = EXIT_SUCCESS;
+out:
+ return ret;
+}
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [RFC 2/3] kbuild: modules: Build and trigger BTI scanner for arm64
2026-10-06 22:18 [RFC 0/3] kbuild: modules: Fixup arm64 BTI relocations Jeremy Linton
2026-10-06 22:18 ` [RFC 1/3] kbuild: modules: Add arm64 BTI fixup utility Jeremy Linton
@ 2026-10-06 22:18 ` Jeremy Linton
2026-10-06 22:28 ` sashiko-bot
2026-10-06 22:18 ` [RFC 3/3] arm64: bti: Drop compiler specific BTI checks Jeremy Linton
` (2 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Jeremy Linton @ 2026-10-06 22:18 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-kbuild, linux-modules, broonie, jpoimboe, nathan, nsc,
mcgrof, petr.pavlu, da.gomez, samitolvanen, atomlin, ndesaulniers,
mark.rutland, will, catalin.marinas, ardb, Emanuele.Rocca,
linux-kernel, Jeremy Linton
Now that we have a utility which can detect and correct missing
landing pads, build it and hook it up to scan during module
finalization.
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
scripts/Makefile | 3 +++
scripts/Makefile.modfinal | 12 +++++++++++-
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/scripts/Makefile b/scripts/Makefile
index 3434a82a119f..10042d5d1251 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -8,6 +8,7 @@ hostprogs-always-$(BUILD_C_RECORDMCOUNT) += recordmcount
hostprogs-always-$(CONFIG_BUILDTIME_TABLE_SORT) += sorttable
hostprogs-always-$(CONFIG_ASN1) += asn1_compiler
hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file
+hostprogs-always-$(CONFIG_ARM64_BTI_KERNEL) += module-bti-check
hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert
hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_builder
hostprogs-always-$(CONFIG_RUST_KERNEL_DOCTESTS) += rustdoc_test_gen
@@ -32,6 +33,8 @@ rustdoc_test_gen-rust := y
HOSTCFLAGS_tracepoint-update.o = -I$(srctree)/tools/include
HOSTCFLAGS_elf-parse.o = -I$(srctree)/tools/include
HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include
+HOSTCFLAGS_module-bti-check.o = -I$(srctree)/tools/include
+HOSTLDLIBS_module-bti-check = -lelf
HOSTLDLIBS_sorttable = -lpthread
HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
HOSTCFLAGS_sign-file.o = $(shell $(HOSTPKG_CONFIG) --cflags libcrypto 2> /dev/null)
diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal
index 01a37ec872b9..973adfa72a7d 100644
--- a/scripts/Makefile.modfinal
+++ b/scripts/Makefile.modfinal
@@ -32,6 +32,12 @@ ifneq ($(WARN_ON_UNUSED_TRACEPOINTS),)
cmd_check_tracepoint = $(objtree)/scripts/tracepoint-update --module $<;
endif
+ifdef CONFIG_ARM64_BTI_KERNEL
+quiet_cmd_bti_check = BTICHECK [M] $@
+ cmd_bti_check = $(objtree)/scripts/module-bti-check --fix $(KBUILD_MODULE_BTI_CHECK_FLAGS) $@
+bti_check_dep = $(objtree)/scripts/module-bti-check
+endif
+
quiet_cmd_ld_ko_o = LD [M] $@
cmd_ld_ko_o = \
$(LD) -r $(KBUILD_LDFLAGS) \
@@ -47,8 +53,12 @@ quiet_cmd_btf_ko = BTF [M] $@
fi;
# Re-generate module BTFs if either module's .ko or vmlinux changed
-%.ko: %.o %.mod.o .module-common.o $(objtree)/scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/vmlinux) FORCE
+%.ko: %.o %.mod.o .module-common.o $(objtree)/scripts/module.lds $(bti_check_dep) $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/vmlinux) FORCE
+$(call if_changed,ld_ko_o)
+ifdef CONFIG_ARM64_BTI_KERNEL
+ +$(call cmd,bti_check)
+endif
+
ifdef CONFIG_DEBUG_INFO_BTF_MODULES
+$(if $(newer-prereqs),$(call cmd,btf_ko))
endif
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [RFC 3/3] arm64: bti: Drop compiler specific BTI checks
2026-10-06 22:18 [RFC 0/3] kbuild: modules: Fixup arm64 BTI relocations Jeremy Linton
2026-10-06 22:18 ` [RFC 1/3] kbuild: modules: Add arm64 BTI fixup utility Jeremy Linton
2026-10-06 22:18 ` [RFC 2/3] kbuild: modules: Build and trigger BTI scanner for arm64 Jeremy Linton
@ 2026-10-06 22:18 ` Jeremy Linton
2026-10-06 22:26 ` sashiko-bot
2026-10-07 8:09 ` [RFC 0/3] kbuild: modules: Fixup arm64 BTI relocations Emanuele Rocca
2026-10-07 8:25 ` Mark Brown
4 siblings, 1 reply; 9+ messages in thread
From: Jeremy Linton @ 2026-10-06 22:18 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-kbuild, linux-modules, broonie, jpoimboe, nathan, nsc,
mcgrof, petr.pavlu, da.gomez, samitolvanen, atomlin, ndesaulniers,
mark.rutland, will, catalin.marinas, ardb, Emanuele.Rocca,
linux-kernel, Jeremy Linton
Now that modules with missing BTI landing pads have veneers explicitly
added, the need for compiler revision specific checks can be dropped.
The link pass will correct the specific cases that both clang and gcc
now generate.
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
arch/arm64/Kconfig | 6 ------
1 file changed, 6 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index cab741a695f5..aea4c34a18bc 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2196,12 +2196,6 @@ config ARM64_BTI_KERNEL
depends on ARM64_BTI
depends on ARM64_PTR_AUTH_KERNEL
depends on CC_HAS_BRANCH_PROT_PAC_RET_BTI
- # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94697
- depends on !CC_IS_GCC || GCC_VERSION >= 100100
- # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106671
- depends on !CC_IS_GCC
- # https://github.com/llvm/llvm-project/issues/215547
- depends on !CC_IS_CLANG || CLANG_VERSION < 210000
depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_ARGS)
help
Build the kernel with Branch Target Identification annotations
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [RFC 3/3] arm64: bti: Drop compiler specific BTI checks
2026-10-06 22:18 ` [RFC 3/3] arm64: bti: Drop compiler specific BTI checks Jeremy Linton
@ 2026-10-06 22:26 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-10-06 22:26 UTC (permalink / raw)
To: Jeremy Linton; +Cc: Petr Pavlu, linux-modules
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] arm64: Kconfig: GCC 9 BTI code generation defect exposed
--
commit 1d7b856a59cb9c3b290733174839f2dcf79cb2c1
Author: Jeremy Linton <jeremy.linton@arm.com>
arm64: bti: Drop compiler specific BTI checks
This commit drops compiler-specific version checks for ARM64_BTI_KERNEL,
relying on a link pass to correct specific cases of missing BTI landing
pads in modules generated by clang and gcc.
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 41ce1fd6ca91e..3c9b89fc215c2 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -2140,12 +2140,6 @@ config ARM64_BTI_KERNEL
> depends on ARM64_BTI
> depends on ARM64_PTR_AUTH_KERNEL
> depends on CC_HAS_BRANCH_PROT_PAC_RET_BTI
> - # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94697
> - depends on !CC_IS_GCC || GCC_VERSION >= 100100
[Severity: High]
Does the newly added module link script mitigate the specific code generation
defect from GCC bug 94697?
The new script scans for and mitigates missing landing pads for cross-section
direct module calls to address GCC bug 106671 and LLVM issue 215547. However,
GCC bug 94697 is a separate defect present in GCC 9 where the compiler fails
to emit BTI landing pads for internal indirect branches to address-taken local
labels.
If the script does not rewrite internal indirect branches, dropping this check
will allow GCC 9 to build a BTI-enabled kernel with incorrectly annotated
machine code. Will this result in runtime Branch Target exceptions when
executing those internal indirect branches?
> - # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106671
> - depends on !CC_IS_GCC
> - # https://github.com/llvm/llvm-project/issues/215547
> - depends on !CC_IS_CLANG || CLANG_VERSION < 210000
> depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_ARGS)
> help
> Build the kernel with Branch Target Identification annotations
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261006221815.2823252-1-jeremy.linton@arm.com?part=3
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC 2/3] kbuild: modules: Build and trigger BTI scanner for arm64
2026-10-06 22:18 ` [RFC 2/3] kbuild: modules: Build and trigger BTI scanner for arm64 Jeremy Linton
@ 2026-10-06 22:28 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-10-06 22:28 UTC (permalink / raw)
To: Jeremy Linton; +Cc: linux-modules, Petr Pavlu
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] scripts/module-bti-check: missing elf_flagdata() on relocation buffer
- [High] kbuild: module-bti-check ignores R_AARCH64_JUMP26 tail calls causing BTI panics
- [Medium] kbuild: unconditional bti_check execution breaks incremental builds
--
commit 6f17af1f0f493574af3f26ef3b98809bf3a9aca7
Author: Jeremy Linton <jeremy.linton@arm.com>
kbuild: modules: Build and trigger BTI scanner for arm64
Now that we have a utility which can detect and correct missing
landing pads, build it and hook it up to scan during module
finalization.
> diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal
> index 01a37ec872b90..973adfa72a7d4 100644
> --- a/scripts/Makefile.modfinal
> +++ b/scripts/Makefile.modfinal
[ ... ]
> @@ -47,8 +53,12 @@ quiet_cmd_btf_ko = BTF [M] $@
> fi;
>
> # Re-generate module BTFs if either module's .ko or vmlinux changed
> -%.ko: %.o %.mod.o .module-common.o $(objtree)/scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/vmlinux) FORCE
> +%.ko: %.o %.mod.o .module-common.o $(objtree)/scripts/module.lds $(bti_check_dep) $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/vmlinux) FORCE
> +$(call if_changed,ld_ko_o)
> +ifdef CONFIG_ARM64_BTI_KERNEL
> + +$(call cmd,bti_check)
> +endif
> +
> ifdef CONFIG_DEBUG_INFO_BTF_MODULES
> +$(if $(newer-prereqs),$(call cmd,btf_ko))
> endif
[Severity: Medium]
Will this execute the bti_check unconditionally on every incremental build?
Since the %.ko target uses FORCE, Kbuild relies on conditional macros to
prevent redundant execution. The bti_check command is not wrapped in an
if_changed guard.
Could this cause module-bti-check --fix to run on all modules every time
Kbuild is invoked, breaking the fast path for null builds?
While reviewing this, I also noticed a couple of regressions in
scripts/module-bti-check.c:
scripts/module-bti-check.c:scan_relocations() {
...
if (!gelf_getrela(data, j, &rela))
goto out_elferr;
if (GELF_R_TYPE(rela.r_info) != R_AARCH64_CALL26)
continue;
...
}
[Severity: High]
Are R_AARCH64_JUMP26 tail calls intentionally filtered out here?
If a module contains a cross-section tail call to a static function, and the
distance requires a PLT, the PLT entry will use an indirect branch to target
the function.
Since static targets don't emit their own BTI pads and the JUMP26 relocation
is bypassed here, wouldn't this indirect branch trigger a BTI exception and a
kernel panic at runtime?
scripts/module-bti-check.c:scan_relocations() {
...
rela.r_info = GELF_R_INFO(veneer->secsym, R_AARCH64_CALL26);
rela.r_addend = veneer->value;
if (!gelf_update_rela(data, j, &rela))
return elf_error(obj);
obj->changed = true;
continue;
...
}
[Severity: High]
Are these modified relocation entries successfully written back to the file?
gelf_update_rela() modifies the Elf_Data relocation block in memory, but the
data block is never flagged as dirty with elf_flagdata().
According to libelf semantics, won't elf_update() silently discard these
relocation changes because the buffer isn't marked dirty?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261006221815.2823252-1-jeremy.linton@arm.com?part=2
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC 1/3] kbuild: modules: Add arm64 BTI fixup utility
2026-10-06 22:18 ` [RFC 1/3] kbuild: modules: Add arm64 BTI fixup utility Jeremy Linton
@ 2026-10-06 22:32 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-10-06 22:32 UTC (permalink / raw)
To: Jeremy Linton; +Cc: Petr Pavlu, linux-modules
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] build: missing elf_flagdata() causes relocation updates to be silently discarded
- [Medium] build: POSIX exit code truncation wraps unfixed BTI counts of exactly 256 to success
- [Medium] scripts: module-bti-check conflates fatal errors with violation counts
--
commit f30f3429bd0a90f5e903b1b7fe22a7c8b76f0249
Author: Jeremy Linton <jeremy.linton@arm.com>
kbuild: modules: Add arm64 BTI fixup utility
This commit introduces a new host build tool, module-bti-check, to verify
and fix up arm64 cross-section module calls that lack BTI landing pads.
It accomplishes this by scanning R_AARCH64_CALL26 relocations and placing
veneers in the target section where necessary.
> diff --git a/scripts/module-bti-check.c b/scripts/module-bti-check.c
> new file mode 100644
> index 0000000000000..c8bef0ed90bb7
> --- /dev/null
> +++ b/scripts/module-bti-check.c
[ ... ]
> if (fix) {
> ret = get_veneer(obj, veneers, &target, &veneer);
> if (ret)
> goto out;
>
> rela.r_info = GELF_R_INFO(veneer->secsym, R_AARCH64_CALL26);
> rela.r_addend = veneer->value;
> if (!gelf_update_rela(data, j, &rela))
> return elf_error(obj);
[Severity: High]
Does this miss setting the libelf dirty flag on the data descriptor?
When gelf_update_rela() is called in scan_relocations(), it updates the
in-memory buffer, but libelf requires elf_flagdata(data, ELF_C_SET,
ELF_F_DIRTY) to actually write the modifications back to the file during
elf_update().
Without the dirty flag, won't the new landing pad veneers be silently
discarded when the updated .rela section is dropped during the file write?
>
> obj->changed = true;
> continue;
> }
[ ... ]
> fprintf(stderr,
> "%s: cross-section call from %s%s%s+0x%llx to %s (%s+0x%llx) lacks a BTI landing pad\n",
> obj->name, source ?: "", source ? " " : "",
> section_name(obj, shdr.sh_info),
> (unsigned long long)rela.r_offset, target.name,
> section_name(obj, target.section_index),
> (unsigned long long)target.value);
>
> unfixed++;
> }
> }
>
> ret = unfixed;
> out:
> return ret;
[Severity: Medium]
Is there a risk of exit code truncation here? scan_relocations() returns
the raw count of unfixed occurrences, which is eventually propagated up
to main() and used as the process exit code.
Since POSIX exit codes are truncated to 8 bits, what happens if the tool
encounters exactly 256 (or 512, etc.) unfixed occurrences? It appears
returning 256 would wrap to 0, which might trick the build system into
treating it as a successful execution despite missing BTI pads.
[ ... ]
> /* Must happen after elf end, to assure correctness */
> while (veneers) {
> struct veneer *next = veneers->next;
>
> free(veneers);
> veneers = next;
> }
>
> if (fd >= 0)
> close(fd);
>
> if (ret < 0) {
> if (ret != -ELIBBAD)
> fprintf(stderr, "%s: %s\n", name, strerror(-ret));
> return EXIT_FAILURE;
> }
>
> return ret;
> }
[Severity: Medium]
Could this error handling conflate fatal OS or libelf errors with violation
counts?
In process_file(), negative error codes like -ENOMEM are converted to
EXIT_FAILURE (which is 1). Because this overlaps with the value returned
when there is exactly 1 unfixed violation, main() cannot differentiate
between a tool failure and a BTI warning.
[ ... ]
> if (elf_version(EV_CURRENT) == EV_NONE) {
> fprintf(stderr, "libelf initialization failed: %s\n", elf_errmsg(-1));
> goto out;
> }
>
> for (i = optind; i < argc; i++) {
> int status = process_file(argv[i], fix);
>
> if (status && !warn) {
> ret = status;
> goto out;
> }
> }
When the --warn flag is active, it ignores all non-zero status codes. Won't
this silently mask build environment failures, returning success even if
the file couldn't be opened or processed?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261006221815.2823252-1-jeremy.linton@arm.com?part=1
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC 0/3] kbuild: modules: Fixup arm64 BTI relocations
2026-10-06 22:18 [RFC 0/3] kbuild: modules: Fixup arm64 BTI relocations Jeremy Linton
` (2 preceding siblings ...)
2026-10-06 22:18 ` [RFC 3/3] arm64: bti: Drop compiler specific BTI checks Jeremy Linton
@ 2026-10-07 8:09 ` Emanuele Rocca
2026-10-07 8:25 ` Mark Brown
4 siblings, 0 replies; 9+ messages in thread
From: Emanuele Rocca @ 2026-10-07 8:09 UTC (permalink / raw)
To: Jeremy Linton
Cc: linux-arm-kernel, linux-kbuild, linux-modules, broonie, jpoimboe,
nathan, nsc, mcgrof, petr.pavlu, da.gomez, samitolvanen, atomlin,
ndesaulniers, mark.rutland, will, catalin.marinas, ardb,
linux-kernel
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@arm.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC 0/3] kbuild: modules: Fixup arm64 BTI relocations
2026-10-06 22:18 [RFC 0/3] kbuild: modules: Fixup arm64 BTI relocations Jeremy Linton
` (3 preceding siblings ...)
2026-10-07 8:09 ` [RFC 0/3] kbuild: modules: Fixup arm64 BTI relocations Emanuele Rocca
@ 2026-10-07 8:25 ` Mark Brown
4 siblings, 0 replies; 9+ messages in thread
From: Mark Brown @ 2026-10-07 8:25 UTC (permalink / raw)
To: Jeremy Linton
Cc: linux-arm-kernel, linux-kbuild, linux-modules, jpoimboe, nathan,
nsc, mcgrof, petr.pavlu, da.gomez, samitolvanen, atomlin,
ndesaulniers, mark.rutland, will, catalin.marinas, ardb,
Emanuele.Rocca, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 380 bytes --]
On Tue, Oct 06, 2026 at 05:18:12PM -0500, 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.
Ard has a series which resolves this in the kernel's module loader:
https://lore.kernel.org/r/20261005110511.157016-4-ardb+git@google.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-10-07 8:25 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-06 22:18 [RFC 0/3] kbuild: modules: Fixup arm64 BTI relocations Jeremy Linton
2026-10-06 22:18 ` [RFC 1/3] kbuild: modules: Add arm64 BTI fixup utility Jeremy Linton
2026-10-06 22:32 ` sashiko-bot
2026-10-06 22:18 ` [RFC 2/3] kbuild: modules: Build and trigger BTI scanner for arm64 Jeremy Linton
2026-10-06 22:28 ` sashiko-bot
2026-10-06 22:18 ` [RFC 3/3] arm64: bti: Drop compiler specific BTI checks Jeremy Linton
2026-10-06 22:26 ` sashiko-bot
2026-10-07 8:09 ` [RFC 0/3] kbuild: modules: Fixup arm64 BTI relocations Emanuele Rocca
2026-10-07 8:25 ` Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox