* [PATCH v2 0/2] arm64: Implement support for BTI veneers
@ 2026-10-05 11:05 Ard Biesheuvel
2026-10-05 11:05 ` [PATCH v2 1/2] arm64: module: Emit BTI veneers for cross-section calls Ard Biesheuvel
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Ard Biesheuvel @ 2026-10-05 11:05 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-kernel, will, catalin.marinas, mark.rutland, Ard Biesheuvel,
Mark Brown, Josh Poimboeuf, Nick Desaulniers
From: Ard Biesheuvel <ardb@kernel.org>
[ Resending this with minimal changes even though some other approaches
were proposed as well. [1][2] Neither of those are appropriate for
backporting, while this series can reasonably be applied to older
kernels. ]
Recent toolchains will omit BTI landing pads from functions with static
linkage that never have their address taken. If a landing pad is needed
nonetheless, it is up to the static linker to emit a BTI veneer withing
direct branching range of the target, and direct the call to the veneer
instead.
Modules are partially linked objects, and so there is no static linker
that can do this for us. Instead, the module loader must see to this.
So implement this for the arm64 module loader. Patch #2 contains a test
module that was used to validate the approach.
Changes since v1:
- make HAVE_LIVE_PATCH depend on !ARM64_BTI_KERNEL, as live patch has
other cases where landing pads may go missing
[1] https://lore.kernel.org/all/cover.1786768375.git.jpoimboe@kernel.org/
[2] https://lore.kernel.org/all/20260822135323.795946-11-ardb+git@google.com/
Cc: Mark Brown <broonie@kernel.org>
Cc: Josh Poimboeuf <jpoimboe@kernel.org>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Ard Biesheuvel (2):
arm64: module: Emit BTI veneers for cross-section calls
DONOTMERGE: arm64: module: Test module for BTI veneers
arch/arm64/Kconfig | 7 +-
arch/arm64/include/asm/module.h | 12 ++
arch/arm64/include/asm/module.lds.h | 3 +
arch/arm64/kernel/Makefile | 1 +
arch/arm64/kernel/bti_veneer_test.c | 26 ++++
arch/arm64/kernel/module-plts.c | 128 +++++++++++++++++++-
6 files changed, 167 insertions(+), 10 deletions(-)
create mode 100644 arch/arm64/kernel/bti_veneer_test.c
--
2.56.0.rc1.315.gc6ed9934b7-goog
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v2 1/2] arm64: module: Emit BTI veneers for cross-section calls 2026-10-05 11:05 [PATCH v2 0/2] arm64: Implement support for BTI veneers Ard Biesheuvel @ 2026-10-05 11:05 ` Ard Biesheuvel 2026-10-05 15:07 ` Mark Brown 2026-11-04 16:28 ` Catalin Marinas 2026-10-05 11:05 ` [PATCH v2 2/2] DONOTMERGE: arm64: module: Test module for BTI veneers Ard Biesheuvel 2026-11-04 8:55 ` [PATCH v2 0/2] arm64: Implement support " Ard Biesheuvel 2 siblings, 2 replies; 6+ messages in thread From: Ard Biesheuvel @ 2026-10-05 11:05 UTC (permalink / raw) To: linux-arm-kernel Cc: linux-kernel, will, catalin.marinas, mark.rutland, Ard Biesheuvel, Mark Brown, Josh Poimboeuf, Nick Desaulniers From: Ard Biesheuvel <ardb@kernel.org> The compiler is permitted to omit BTI landing pads from static functions that never have their address taken, but are only called directly, even if those calls originate from other code sections. This means that calls into a module's .text section from .init.text, which may need to be routed via a PLT if .text is out of direct branching range, may result in BTI exceptions due to the indirect calls performed by the PLT veneers. (Note that calls to .init.text from .text are not allowed.) The 'solution' is to emit yet another veneer - this is what the ELF psABI for AArch64 mandates in this case. So derive an upper bound for the number of veneers that may be needed in the core module region to ensure that any call from init code that ends up needing a PLT can be directed at a veneer with a BTI landing pad, and allocate the additional space. Then, emit these veneers as needed, i.e., only when emitting a PLT entry for a call from an init code section to a normal code section in the same module. In practice, this only occurs when a module's .init.text happens to be allocated far away from its .text section, which might happen when the initial 128M 'near' module region runs out of space between allocating the core module and allocating its init region. Signed-off-by: Ard Biesheuvel <ardb@kernel.org> --- arch/arm64/Kconfig | 7 +- arch/arm64/include/asm/module.h | 12 ++ arch/arm64/include/asm/module.lds.h | 3 + arch/arm64/kernel/module-plts.c | 128 +++++++++++++++++++- 4 files changed, 140 insertions(+), 10 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index cab741a695f5..23879cb05d6b 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -210,7 +210,8 @@ config ARM64 select HAVE_HW_BREAKPOINT if PERF_EVENTS select HAVE_IOREMAP_PROT select HAVE_IRQ_TIME_ACCOUNTING - select HAVE_LIVEPATCH + # https://lore.kernel.org/all/20260812162058.612202-5-ardb@kernel.org/ + select HAVE_LIVEPATCH if !ARM64_BTI_KERNEL select HAVE_MOD_ARCH_SPECIFIC select HAVE_NMI select HAVE_PERF_EVENTS @@ -2198,10 +2199,6 @@ config ARM64_BTI_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 diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h index fb9b88eebeb1..0bdac3db5719 100644 --- a/arch/arm64/include/asm/module.h +++ b/arch/arm64/include/asm/module.h @@ -16,6 +16,7 @@ struct mod_plt_sec { struct mod_arch_specific { struct mod_plt_sec core; struct mod_plt_sec init; + struct mod_plt_sec bti; /* for CONFIG_DYNAMIC_FTRACE */ struct plt_entry *ftrace_trampolines; @@ -43,6 +44,17 @@ struct plt_entry { __le32 br; /* br x16 */ }; +struct bti_veneer { + /* + * Functions with static linkage may lack BTI landing pads if their + * address is never taken. E.g., a direct call from .init.text to a + * static function in .text may need an additional veneer at the target + * end if it is routed via a PLT entry. + */ + __le32 bti_c; + __le32 b; +}; + static inline bool is_forbidden_offset_for_adrp(void *place) { return cpus_have_final_cap(ARM64_WORKAROUND_843419) && diff --git a/arch/arm64/include/asm/module.lds.h b/arch/arm64/include/asm/module.lds.h index 603f92a8a73e..52bd10766803 100644 --- a/arch/arm64/include/asm/module.lds.h +++ b/arch/arm64/include/asm/module.lds.h @@ -1,6 +1,9 @@ SECTIONS { .plt 0 : { BYTE(0) } .init.plt 0 : { BYTE(0) } +#ifdef CONFIG_ARM64_BTI_KERNEL + .text.bti_veneer 0 : { BYTE(0) } +#endif .text.ftrace_trampoline 0 : { BYTE(0) } .init.text.ftrace_trampoline 0 : { BYTE(0) } diff --git a/arch/arm64/kernel/module-plts.c b/arch/arm64/kernel/module-plts.c index 7afd370da9f4..e2c009cce96c 100644 --- a/arch/arm64/kernel/module-plts.c +++ b/arch/arm64/kernel/module-plts.c @@ -66,12 +66,48 @@ static bool plt_entries_equal(const struct plt_entry *a, (q + aarch64_insn_adrp_get_offset(le32_to_cpu(b->adrp))); } +static u64 module_emit_bti_veneer(struct module *mod, const Elf64_Shdr *sechdrs, + u64 target) +{ + struct mod_plt_sec *pltsec = &mod->arch.bti; + struct bti_veneer *btiv = (void *)sechdrs[pltsec->plt_shndx].sh_addr; + + /* Look for an existing entry pointing to 'target' */ + for (int i = 0; i < pltsec->plt_num_entries; i++) { + u64 dst = (u64)&btiv[i].b + + aarch64_get_branch_offset(btiv[i].b); + if (dst == target) + return (u64)&btiv[i]; + } + + /* Allocate a new veneer */ + if (WARN_ON(pltsec->plt_num_entries >= pltsec->plt_max_entries)) + return 0; + + btiv += pltsec->plt_num_entries++; + + btiv->bti_c = aarch64_insn_gen_hint(AARCH64_INSN_HINT_BTIC); + btiv->b = aarch64_insn_gen_branch_imm((u64)&btiv->b, target, + AARCH64_INSN_BRANCH_NOLINK); + + return (u64)btiv; +} + +static bool target_needs_bti_veneer(struct module *mod, const Elf64_Sym *sym) +{ + if (sym->st_shndx == STN_UNDEF || + ELF64_ST_BIND(sym->st_info) != STB_LOCAL) + return false; + + return !within_module_init((unsigned long)sym->st_value, mod); +} + u64 module_emit_plt_entry(struct module *mod, Elf64_Shdr *sechdrs, void *loc, const Elf64_Rela *rela, Elf64_Sym *sym) { - struct mod_plt_sec *pltsec = !within_module_init((unsigned long)loc, mod) ? - &mod->arch.core : &mod->arch.init; + bool is_init = within_module_init((unsigned long)loc, mod); + struct mod_plt_sec *pltsec = !is_init ? &mod->arch.core : &mod->arch.init; struct plt_entry *plt = (struct plt_entry *)sechdrs[pltsec->plt_shndx].sh_addr; int i = pltsec->plt_num_entries; int j = i - 1; @@ -80,6 +116,16 @@ u64 module_emit_plt_entry(struct module *mod, Elf64_Shdr *sechdrs, if (is_forbidden_offset_for_adrp(&plt[i].adrp)) i++; + if (system_supports_bti_kernel() && is_init) { + /* + * Check if the target is a function with static linkage within + * the same module but in a non-init section: if so, point the + * PLT entry at a BTI veneer instead. + */ + if (target_needs_bti_veneer(mod, sym)) + val = module_emit_bti_veneer(mod, sechdrs, val); + } + plt[i] = get_plt_entry(val, &plt[i]); /* @@ -277,11 +323,66 @@ static int partition_branch_plt_relas(Elf64_Sym *syms, Elf64_Rela *rela, return i; } +static int count_bti_veneers(const Elf_Ehdr *ehdr, const Elf_Shdr *sechdrs, + const char *secstrings, const Elf64_Sym *syms, + Elf64_Word cur) +{ + int count = 0; + + if (!system_supports_bti_kernel()) + return 0; + + /* + * BTI veneers must be emitted within direct branching range of the + * target function, so that PLTs emitted to perform calls that exceed + * that range can use indirect calls as usual, even if the target + * function lacks a landing pad. This is needed between init code + * sections and normal code sections, which can be loaded far away from + * each other. It should never be needed the other way around, given + * that normal code cannot call init code. + * + * So go over init code sections, and find call/jump relocations + * referring to symbols in the current section. If the symbol has + * static linkage, allocate space for a BTI veneer. + */ + + for (int i = 0; i < ehdr->e_shnum; i++) { + if (sechdrs[i].sh_type != SHT_RELA) + continue; + + const Elf64_Shdr *dstsec = sechdrs + sechdrs[i].sh_info; + + /* Ignore relocations that operate on non-exec sections */ + if (!(dstsec->sh_flags & SHF_EXECINSTR)) + continue; + + /* Only look at .init code sections */ + if (!module_init_layout_section(secstrings + dstsec->sh_name)) + continue; + + Elf64_Rela *rela = (void *)ehdr + sechdrs[i].sh_offset; + int num = sechdrs[i].sh_size / sizeof(Elf64_Rela); + for (int j = 0; j < num; j++) { + const Elf64_Sym *s = syms + ELF64_R_SYM(rela[j].r_info); + + switch (ELF64_R_TYPE(rela[j].r_info)) { + case R_AARCH64_JUMP26: + case R_AARCH64_CALL26: + if (s->st_shndx == cur && + ELF64_ST_BIND(s->st_info) == STB_LOCAL) + count++; + } + } + } + return count; +} + int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, char *secstrings, struct module *mod) { unsigned long core_plts = 0; unsigned long init_plts = 0; + unsigned long bti_veneers = 0; Elf64_Sym *syms = NULL; Elf_Shdr *pltsec, *tramp = NULL, *init_tramp = NULL; int i; @@ -295,6 +396,8 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, mod->arch.core.plt_shndx = i; else if (!strcmp(secstrings + sechdrs[i].sh_name, ".init.plt")) mod->arch.init.plt_shndx = i; + else if (!strcmp(secstrings + sechdrs[i].sh_name, ".text.bti_veneer")) + mod->arch.bti.plt_shndx = i; else if (!strcmp(secstrings + sechdrs[i].sh_name, ".text.ftrace_trampoline")) tramp = sechdrs + i; @@ -305,7 +408,8 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, syms = (Elf64_Sym *)sechdrs[i].sh_addr; } - if (!mod->arch.core.plt_shndx || !mod->arch.init.plt_shndx) { + if (!mod->arch.core.plt_shndx || !mod->arch.init.plt_shndx || + (IS_ENABLED(CONFIG_ARM64_BTI_KERNEL) && !mod->arch.bti.plt_shndx)) { pr_err("%s: module PLT section(s) missing\n", mod->name); return -ENOEXEC; } @@ -335,12 +439,16 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, if (nents) sort(rels, nents, sizeof(Elf64_Rela), cmp_rela, NULL); - if (!module_init_layout_section(secstrings + dstsec->sh_name)) + if (!module_init_layout_section(secstrings + dstsec->sh_name)) { core_plts += count_plts(syms, rels, numrels, sechdrs[i].sh_info, dstsec); - else + bti_veneers += count_bti_veneers(ehdr, sechdrs, + secstrings, syms, + sechdrs[i].sh_info); + } else { init_plts += count_plts(syms, rels, numrels, sechdrs[i].sh_info, dstsec); + } } pltsec = sechdrs + mod->arch.core.plt_shndx; @@ -359,6 +467,16 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, mod->arch.init.plt_num_entries = 0; mod->arch.init.plt_max_entries = init_plts; + if (system_supports_bti_kernel()) { + pltsec = sechdrs + mod->arch.bti.plt_shndx; + pltsec->sh_type = SHT_NOBITS; + pltsec->sh_flags = SHF_EXECINSTR | SHF_ALLOC; + pltsec->sh_addralign = L1_CACHE_BYTES; + pltsec->sh_size = (bti_veneers + 1) * sizeof(struct bti_veneer); + mod->arch.bti.plt_num_entries = 0; + mod->arch.bti.plt_max_entries = bti_veneers; + } + if (tramp) { tramp->sh_type = SHT_NOBITS; tramp->sh_flags = SHF_EXECINSTR | SHF_ALLOC; -- 2.56.0.rc1.315.gc6ed9934b7-goog ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] arm64: module: Emit BTI veneers for cross-section calls 2026-10-05 11:05 ` [PATCH v2 1/2] arm64: module: Emit BTI veneers for cross-section calls Ard Biesheuvel @ 2026-10-05 15:07 ` Mark Brown 2026-11-04 16:28 ` Catalin Marinas 1 sibling, 0 replies; 6+ messages in thread From: Mark Brown @ 2026-10-05 15:07 UTC (permalink / raw) To: Ard Biesheuvel Cc: linux-arm-kernel, linux-kernel, will, catalin.marinas, mark.rutland, Ard Biesheuvel, Josh Poimboeuf, Nick Desaulniers [-- Attachment #1: Type: text/plain, Size: 602 bytes --] On Mon, Oct 05, 2026 at 01:05:13PM +0200, Ard Biesheuvel wrote: > This means that calls into a module's .text section from .init.text, > which may need to be routed via a PLT if .text is out of direct > branching range, may result in BTI exceptions due to the indirect calls > performed by the PLT veneers. (Note that calls to .init.text from .text > are not allowed.) > The 'solution' is to emit yet another veneer - this is what the ELF > psABI for AArch64 mandates in this case. Thanks for doing this - it'd be great to finally get something like this merged, it's been sitting for far too long. [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/2] arm64: module: Emit BTI veneers for cross-section calls 2026-10-05 11:05 ` [PATCH v2 1/2] arm64: module: Emit BTI veneers for cross-section calls Ard Biesheuvel 2026-10-05 15:07 ` Mark Brown @ 2026-11-04 16:28 ` Catalin Marinas 1 sibling, 0 replies; 6+ messages in thread From: Catalin Marinas @ 2026-11-04 16:28 UTC (permalink / raw) To: Ard Biesheuvel Cc: linux-arm-kernel, linux-kernel, will, mark.rutland, Ard Biesheuvel, Mark Brown, Josh Poimboeuf, Nick Desaulniers On Mon, Oct 05, 2026 at 01:05:13PM +0200, Ard Biesheuvel wrote: > From: Ard Biesheuvel <ardb@kernel.org> > > The compiler is permitted to omit BTI landing pads from static functions > that never have their address taken, but are only called directly, even > if those calls originate from other code sections. > > This means that calls into a module's .text section from .init.text, > which may need to be routed via a PLT if .text is out of direct > branching range, may result in BTI exceptions due to the indirect calls > performed by the PLT veneers. (Note that calls to .init.text from .text > are not allowed.) > > The 'solution' is to emit yet another veneer - this is what the ELF > psABI for AArch64 mandates in this case. > > So derive an upper bound for the number of veneers that may be needed in > the core module region to ensure that any call from init code that ends > up needing a PLT can be directed at a veneer with a BTI landing pad, and > allocate the additional space. > > Then, emit these veneers as needed, i.e., only when emitting a PLT entry > for a call from an init code section to a normal code section in the > same module. In practice, this only occurs when a module's .init.text > happens to be allocated far away from its .text section, which might > happen when the initial 128M 'near' module region runs out of space > between allocating the core module and allocating its init region. > > Signed-off-by: Ard Biesheuvel <ardb@kernel.org> > --- > arch/arm64/Kconfig | 7 +- > arch/arm64/include/asm/module.h | 12 ++ > arch/arm64/include/asm/module.lds.h | 3 + > arch/arm64/kernel/module-plts.c | 128 +++++++++++++++++++- > 4 files changed, 140 insertions(+), 10 deletions(-) > > diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig > index cab741a695f5..23879cb05d6b 100644 > --- a/arch/arm64/Kconfig > +++ b/arch/arm64/Kconfig > @@ -210,7 +210,8 @@ config ARM64 > select HAVE_HW_BREAKPOINT if PERF_EVENTS > select HAVE_IOREMAP_PROT > select HAVE_IRQ_TIME_ACCOUNTING > - select HAVE_LIVEPATCH > + # https://lore.kernel.org/all/20260812162058.612202-5-ardb@kernel.org/ > + select HAVE_LIVEPATCH if !ARM64_BTI_KERNEL > select HAVE_MOD_ARCH_SPECIFIC > select HAVE_NMI > select HAVE_PERF_EVENTS > @@ -2198,10 +2199,6 @@ config ARM64_BTI_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 I think this should be the other way around (and keep HAVE_LIVEPATCH unconditional): config ARM64_BTI_KERNEL ... depends on !LIVEPATCH || (CC_IS_CLANG && CLANG_VERSION < 210000) I also wonder whether dropping the compiler dependency should come with some sanity check/assert for (the unlikely case) of a large vmlinux, similar to one of Josh's patches or a boot-time check that skips enabling BTI. At least until we get some generic compiler/linker workaround for large images: https://lore.kernel.org/all/8932e59a4f6e8383f37078dada1f23639b85a035.1786768375.git.jpoimboe@kernel.org/ There are some Sashiko comments. I'd ignore the big-endian ones since we removed it and it had been marked broken for some time anyway. But the other points look valid. https://sashiko.dev/#/patchset/20261005110511.157016-4-ardb+git@google.com Apart from those, I don't have other technical objections to the patch but I wonder whether we'll find alternative options going forward that make this fix redundant. E.g. allocating .init.text and .text together (you had an RFC) or a new execmem_alloc_near() to try to place them nearby. In the meantime, would something like the following work for us instead of the veneers? We won't free the .init.text module section but this should be small. There's the ppc64 precedent. bool module_init_section(const char *name) { if (system_supports_bti_kernel() && strstarts(name, ".init.text")) return false; return strstarts(name, ".init"); } -- Catalin ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 2/2] DONOTMERGE: arm64: module: Test module for BTI veneers 2026-10-05 11:05 [PATCH v2 0/2] arm64: Implement support for BTI veneers Ard Biesheuvel 2026-10-05 11:05 ` [PATCH v2 1/2] arm64: module: Emit BTI veneers for cross-section calls Ard Biesheuvel @ 2026-10-05 11:05 ` Ard Biesheuvel 2026-11-04 8:55 ` [PATCH v2 0/2] arm64: Implement support " Ard Biesheuvel 2 siblings, 0 replies; 6+ messages in thread From: Ard Biesheuvel @ 2026-10-05 11:05 UTC (permalink / raw) To: linux-arm-kernel Cc: linux-kernel, will, catalin.marinas, mark.rutland, Ard Biesheuvel, Mark Brown, Josh Poimboeuf, Nick Desaulniers From: Ard Biesheuvel <ardb@kernel.org> This module has a tiny .text section with a static function, which is called by the module init hook, which is placed in a ~128M init code section, which is therefore guaranteed to be place out of direct branching range when CONFIG_RANDOMIZE_MODULE_REGION_FULL is disabled. When CONFIG_ARM64_BTI_KERNEL is enabled, this forces the use of a BTI veneer, as recent GCCs and Clangs will elide BTI landing pads for static functions that never have their address taken, even in the presence of cross-section calls to those functions. Signed-off-by: Ard Biesheuvel <ardb@kernel.org> --- arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/bti_veneer_test.c | 26 ++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index d2690c3ec528..b74e2dbd2d5f 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_ARM64_MPAM) += mpam.o obj-$(CONFIG_ARM64_MTE) += mte.o obj-y += vdso-wrap.o obj-$(CONFIG_COMPAT_VDSO) += vdso32-wrap.o +obj-m += bti_veneer_test.o # Force dependency (vdso*-wrap.S includes vdso.so through incbin) $(obj)/vdso-wrap.o: $(obj)/vdso/vdso.so diff --git a/arch/arm64/kernel/bti_veneer_test.c b/arch/arm64/kernel/bti_veneer_test.c new file mode 100644 index 000000000000..62c20e960d8d --- /dev/null +++ b/arch/arm64/kernel/bti_veneer_test.c @@ -0,0 +1,26 @@ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> + +static int noinline static_noninit_function(void) +{ + static volatile int ret; + return ret; +} + +static int __init bti_veneer_test_init(void) +{ + return static_noninit_function(); +} +module_init(bti_veneer_test_init); + +static void bti_veneer_test_exit(void) +{ +} +module_exit(bti_veneer_test_exit); + +/* Make the init code region too big to fit in 128M 'near' module region */ +asm(".section .init.padding, \"ax\", %progbits; .space (128 << 20) - 64; .previous"); + +MODULE_LICENSE("GPL"); -- 2.56.0.rc1.315.gc6ed9934b7-goog ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 0/2] arm64: Implement support for BTI veneers 2026-10-05 11:05 [PATCH v2 0/2] arm64: Implement support for BTI veneers Ard Biesheuvel 2026-10-05 11:05 ` [PATCH v2 1/2] arm64: module: Emit BTI veneers for cross-section calls Ard Biesheuvel 2026-10-05 11:05 ` [PATCH v2 2/2] DONOTMERGE: arm64: module: Test module for BTI veneers Ard Biesheuvel @ 2026-11-04 8:55 ` Ard Biesheuvel 2 siblings, 0 replies; 6+ messages in thread From: Ard Biesheuvel @ 2026-11-04 8:55 UTC (permalink / raw) To: Ard Biesheuvel, linux-arm-kernel Cc: Will Deacon, Catalin Marinas, Mark Rutland, Mark Brown, Josh Poimboeuf, Nick Desaulniers, linux-hardening On Mon, 5 Oct 2026, at 13:05, Ard Biesheuvel wrote: > From: Ard Biesheuvel <ardb@kernel.org> > > [ Resending this with minimal changes even though some other approaches > were proposed as well. [1][2] Neither of those are appropriate for > backporting, while this series can reasonably be applied to older > kernels. ] > > Recent toolchains will omit BTI landing pads from functions with static > linkage that never have their address taken. If a landing pad is needed > nonetheless, it is up to the static linker to emit a BTI veneer withing > direct branching range of the target, and direct the call to the veneer > instead. > > Modules are partially linked objects, and so there is no static linker > that can do this for us. Instead, the module loader must see to this. > > So implement this for the arm64 module loader. Patch #2 contains a test > module that was used to validate the approach. > > Changes since v1: > - make HAVE_LIVE_PATCH depend on !ARM64_BTI_KERNEL, as live patch has > other cases where landing pads may go missing > > [1] https://lore.kernel.org/all/cover.1786768375.git.jpoimboe@kernel.org/ > [2] https://lore.kernel.org/all/20260822135323.795946-11-ardb+git@google.com/ > > Cc: Mark Brown <broonie@kernel.org> > Cc: Josh Poimboeuf <jpoimboe@kernel.org> > Cc: Nick Desaulniers <ndesaulniers@google.com> > > Ard Biesheuvel (2): > arm64: module: Emit BTI veneers for cross-section calls > DONOTMERGE: arm64: module: Test module for BTI veneers > Ping? ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-11-04 16:28 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-05 11:05 [PATCH v2 0/2] arm64: Implement support for BTI veneers Ard Biesheuvel 2026-10-05 11:05 ` [PATCH v2 1/2] arm64: module: Emit BTI veneers for cross-section calls Ard Biesheuvel 2026-10-05 15:07 ` Mark Brown 2026-11-04 16:28 ` Catalin Marinas 2026-10-05 11:05 ` [PATCH v2 2/2] DONOTMERGE: arm64: module: Test module for BTI veneers Ard Biesheuvel 2026-11-04 8:55 ` [PATCH v2 0/2] arm64: Implement support " Ard Biesheuvel
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox