Skip to content

Commit 6bb712a

Browse files
panfan-qcomgregkh
authored andcommitted
arm64: ftrace: fix unreachable PLT for ftrace_caller in init_module with CONFIG_DYNAMIC_FTRACE
commit a7ed7b9 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 3e35d30 ("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: 3e35d30 ("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>
1 parent 01352cf commit 6bb712a

File tree

5 files changed

+34
-4
lines changed

5 files changed

+34
-4
lines changed

arch/arm64/include/asm/module.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ struct mod_arch_specific {
1919

2020
/* for CONFIG_DYNAMIC_FTRACE */
2121
struct plt_entry *ftrace_trampolines;
22+
struct plt_entry *init_ftrace_trampolines;
2223
};
2324

2425
u64 module_emit_plt_entry(struct module *mod, Elf64_Shdr *sechdrs,

arch/arm64/include/asm/module.lds.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ SECTIONS {
22
.plt 0 : { BYTE(0) }
33
.init.plt 0 : { BYTE(0) }
44
.text.ftrace_trampoline 0 : { BYTE(0) }
5+
.init.text.ftrace_trampoline 0 : { BYTE(0) }
56

67
#ifdef CONFIG_KASAN_SW_TAGS
78
/*

arch/arm64/kernel/ftrace.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,17 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
258258
return ftrace_modify_code(pc, 0, new, false);
259259
}
260260

261-
static struct plt_entry *get_ftrace_plt(struct module *mod)
261+
static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr)
262262
{
263263
#ifdef CONFIG_MODULES
264-
struct plt_entry *plt = mod->arch.ftrace_trampolines;
264+
struct plt_entry *plt = NULL;
265+
266+
if (within_module_mem_type(addr, mod, MOD_INIT_TEXT))
267+
plt = mod->arch.init_ftrace_trampolines;
268+
else if (within_module_mem_type(addr, mod, MOD_TEXT))
269+
plt = mod->arch.ftrace_trampolines;
270+
else
271+
return NULL;
265272

266273
return &plt[FTRACE_PLT_IDX];
267274
#else
@@ -332,7 +339,7 @@ static bool ftrace_find_callable_addr(struct dyn_ftrace *rec,
332339
if (WARN_ON(!mod))
333340
return false;
334341

335-
plt = get_ftrace_plt(mod);
342+
plt = get_ftrace_plt(mod, pc);
336343
if (!plt) {
337344
pr_err("ftrace: no module PLT for %ps\n", (void *)*addr);
338345
return false;

arch/arm64/kernel/module-plts.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
283283
unsigned long core_plts = 0;
284284
unsigned long init_plts = 0;
285285
Elf64_Sym *syms = NULL;
286-
Elf_Shdr *pltsec, *tramp = NULL;
286+
Elf_Shdr *pltsec, *tramp = NULL, *init_tramp = NULL;
287287
int i;
288288

289289
/*
@@ -298,6 +298,9 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
298298
else if (!strcmp(secstrings + sechdrs[i].sh_name,
299299
".text.ftrace_trampoline"))
300300
tramp = sechdrs + i;
301+
else if (!strcmp(secstrings + sechdrs[i].sh_name,
302+
".init.text.ftrace_trampoline"))
303+
init_tramp = sechdrs + i;
301304
else if (sechdrs[i].sh_type == SHT_SYMTAB)
302305
syms = (Elf64_Sym *)sechdrs[i].sh_addr;
303306
}
@@ -363,5 +366,12 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
363366
tramp->sh_size = NR_FTRACE_PLTS * sizeof(struct plt_entry);
364367
}
365368

369+
if (init_tramp) {
370+
init_tramp->sh_type = SHT_NOBITS;
371+
init_tramp->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
372+
init_tramp->sh_addralign = __alignof__(struct plt_entry);
373+
init_tramp->sh_size = NR_FTRACE_PLTS * sizeof(struct plt_entry);
374+
}
375+
366376
return 0;
367377
}

arch/arm64/kernel/module.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,17 @@ static int module_init_ftrace_plt(const Elf_Ehdr *hdr,
453453
__init_plt(&plts[FTRACE_PLT_IDX], FTRACE_ADDR);
454454

455455
mod->arch.ftrace_trampolines = plts;
456+
457+
s = find_section(hdr, sechdrs, ".init.text.ftrace_trampoline");
458+
if (!s)
459+
return -ENOEXEC;
460+
461+
plts = (void *)s->sh_addr;
462+
463+
__init_plt(&plts[FTRACE_PLT_IDX], FTRACE_ADDR);
464+
465+
mod->arch.init_ftrace_trampolines = plts;
466+
456467
#endif
457468
return 0;
458469
}

0 commit comments

Comments
 (0)