]> git.ipfire.org Git - thirdparty/kernel/stable.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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 9 Sep 2025 16:56:26 +0000 (18:56 +0200)
commit a7ed7b9d0ebb038db9963d574da0311cab0b666a upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
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 bfa6638b4c930ce11cc2b3462a802581a141fcfe..8f7ac23c404d99a1d70003ac5edb073659e932c9 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 a650f5e11fc5d8614a4656b92cce3c4c446eb16f..b657f058bf4d50a744d1ddc01baea06f0b813f73 100644 (file)
@@ -195,10 +195,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
@@ -270,7 +277,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 79200f21e1239303fcc03062216278bd7118c4a0..e4ddb1642ee22dc4357c7d48250d0351040f368c 100644 (file)
@@ -284,7 +284,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;
 
        /*
@@ -299,6 +299,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;
        }
@@ -364,5 +367,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 dd851297596e5e9372bf4f64f640283181e86395..adaf2920773b37103e221bb091d61aaea2b1bfad 100644 (file)
@@ -579,6 +579,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;
 }