]> www.infradead.org Git - users/griffoul/linux.git/commitdiff
arm64: ftrace: fix unreachable PLT for ftrace_caller in init_module with CONFIG_DYNAM...
authorpanfan <panfan@qti.qualcomm.com>
Fri, 5 Sep 2025 03:22:36 +0000 (20:22 -0700)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 5 Sep 2025 15:56:20 +0000 (16:56 +0100)
On arm64, it has been possible for a module's sections to be placed more
than 128M away from each other since commit:

  commit 3e35d303ab7d ("arm64: module: rework module VA range selection")

Due to this, an ftrace callsite in a module's .init.text section can be
out of branch range for the module's ftrace PLT entry (in the module's
.text section). Any attempt to enable tracing of that callsite will
result in a BRK being patched into the callsite, resulting in a fatal
exception when the callsite is later executed.

Fix this by adding an additional trampoline for .init.text, which will
be within range.

No additional trampolines are necessary due to the way a given
module's executable sections are packed together. Any executable
section beginning with ".init" will be placed in MOD_INIT_TEXT,
and any other executable section, including those beginning with ".exit",
 will be placed in MOD_TEXT.

Fixes: 3e35d303ab7d ("arm64: module: rework module VA range selection")
Cc: <stable@vger.kernel.org> # 6.5.x
Signed-off-by: panfan <panfan@qti.qualcomm.com>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Link: https://lore.kernel.org/r/20250905032236.3220885-1-panfan@qti.qualcomm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/include/asm/module.h
arch/arm64/include/asm/module.lds.h
arch/arm64/kernel/ftrace.c
arch/arm64/kernel/module-plts.c
arch/arm64/kernel/module.c

index 79550b22ba19ce2dc40939251c8d6712021a61d3..fb9b88eebeb15ac37d7c5fb304f03336949ae783 100644 (file)
@@ -19,6 +19,7 @@ struct mod_arch_specific {
 
        /* for CONFIG_DYNAMIC_FTRACE */
        struct plt_entry        *ftrace_trampolines;
+       struct plt_entry        *init_ftrace_trampolines;
 };
 
 u64 module_emit_plt_entry(struct module *mod, Elf64_Shdr *sechdrs,
index b9ae8349e35dbb79b9192a23b2e71a0f73b25f63..fb944b46846dae9d567973f754aedf71e195a911 100644 (file)
@@ -2,6 +2,7 @@ SECTIONS {
        .plt 0 : { BYTE(0) }
        .init.plt 0 : { BYTE(0) }
        .text.ftrace_trampoline 0 : { BYTE(0) }
+       .init.text.ftrace_trampoline 0 : { BYTE(0) }
 
 #ifdef CONFIG_KASAN_SW_TAGS
        /*
index 5a890714ee2e987b6712b2aff852c1994940d6d6..5adad37ab4faff70a7755304b1e8a2e8072d1276 100644 (file)
@@ -258,10 +258,17 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
        return ftrace_modify_code(pc, 0, new, false);
 }
 
-static struct plt_entry *get_ftrace_plt(struct module *mod)
+static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr)
 {
 #ifdef CONFIG_MODULES
-       struct plt_entry *plt = mod->arch.ftrace_trampolines;
+       struct plt_entry *plt = NULL;
+
+       if (within_module_mem_type(addr, mod, MOD_INIT_TEXT))
+               plt = mod->arch.init_ftrace_trampolines;
+       else if (within_module_mem_type(addr, mod, MOD_TEXT))
+               plt = mod->arch.ftrace_trampolines;
+       else
+               return NULL;
 
        return &plt[FTRACE_PLT_IDX];
 #else
@@ -332,7 +339,7 @@ static bool ftrace_find_callable_addr(struct dyn_ftrace *rec,
        if (WARN_ON(!mod))
                return false;
 
-       plt = get_ftrace_plt(mod);
+       plt = get_ftrace_plt(mod, pc);
        if (!plt) {
                pr_err("ftrace: no module PLT for %ps\n", (void *)*addr);
                return false;
index bde32979c06afc18366f228459f2f579665befc0..7afd370da9f48fe0d0d8791c07676b05a6fe9240 100644 (file)
@@ -283,7 +283,7 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
        unsigned long core_plts = 0;
        unsigned long init_plts = 0;
        Elf64_Sym *syms = NULL;
-       Elf_Shdr *pltsec, *tramp = NULL;
+       Elf_Shdr *pltsec, *tramp = NULL, *init_tramp = NULL;
        int i;
 
        /*
@@ -298,6 +298,9 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
                else if (!strcmp(secstrings + sechdrs[i].sh_name,
                                 ".text.ftrace_trampoline"))
                        tramp = sechdrs + i;
+               else if (!strcmp(secstrings + sechdrs[i].sh_name,
+                                ".init.text.ftrace_trampoline"))
+                       init_tramp = sechdrs + i;
                else if (sechdrs[i].sh_type == SHT_SYMTAB)
                        syms = (Elf64_Sym *)sechdrs[i].sh_addr;
        }
@@ -363,5 +366,12 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
                tramp->sh_size = NR_FTRACE_PLTS * sizeof(struct plt_entry);
        }
 
+       if (init_tramp) {
+               init_tramp->sh_type = SHT_NOBITS;
+               init_tramp->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+               init_tramp->sh_addralign = __alignof__(struct plt_entry);
+               init_tramp->sh_size = NR_FTRACE_PLTS * sizeof(struct plt_entry);
+       }
+
        return 0;
 }
index 40148d2725cedacea5d08e32b8428a80ab8b40d7..d6d443c4a01aca6bcd2b8aa96594f964c6a4e840 100644 (file)
@@ -466,6 +466,17 @@ static int module_init_ftrace_plt(const Elf_Ehdr *hdr,
        __init_plt(&plts[FTRACE_PLT_IDX], FTRACE_ADDR);
 
        mod->arch.ftrace_trampolines = plts;
+
+       s = find_section(hdr, sechdrs, ".init.text.ftrace_trampoline");
+       if (!s)
+               return -ENOEXEC;
+
+       plts = (void *)s->sh_addr;
+
+       __init_plt(&plts[FTRACE_PLT_IDX], FTRACE_ADDR);
+
+       mod->arch.init_ftrace_trampolines = plts;
+
 #endif
        return 0;
 }