]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
19d54ad0f79af4facb0e7511c47b9fefad816a45
[thirdparty/kernel/stable-queue.git] /
1 From a7ed7b9d0ebb038db9963d574da0311cab0b666a Mon Sep 17 00:00:00 2001
2 From: panfan <panfan@qti.qualcomm.com>
3 Date: Thu, 4 Sep 2025 20:22:36 -0700
4 Subject: arm64: ftrace: fix unreachable PLT for ftrace_caller in init_module with CONFIG_DYNAMIC_FTRACE
5
6 From: panfan <panfan@qti.qualcomm.com>
7
8 commit a7ed7b9d0ebb038db9963d574da0311cab0b666a upstream.
9
10 On arm64, it has been possible for a module's sections to be placed more
11 than 128M away from each other since commit:
12
13 commit 3e35d303ab7d ("arm64: module: rework module VA range selection")
14
15 Due to this, an ftrace callsite in a module's .init.text section can be
16 out of branch range for the module's ftrace PLT entry (in the module's
17 .text section). Any attempt to enable tracing of that callsite will
18 result in a BRK being patched into the callsite, resulting in a fatal
19 exception when the callsite is later executed.
20
21 Fix this by adding an additional trampoline for .init.text, which will
22 be within range.
23
24 No additional trampolines are necessary due to the way a given
25 module's executable sections are packed together. Any executable
26 section beginning with ".init" will be placed in MOD_INIT_TEXT,
27 and any other executable section, including those beginning with ".exit",
28 will be placed in MOD_TEXT.
29
30 Fixes: 3e35d303ab7d ("arm64: module: rework module VA range selection")
31 Cc: <stable@vger.kernel.org> # 6.5.x
32 Signed-off-by: panfan <panfan@qti.qualcomm.com>
33 Acked-by: Mark Rutland <mark.rutland@arm.com>
34 Link: https://lore.kernel.org/r/20250905032236.3220885-1-panfan@qti.qualcomm.com
35 Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
36 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
37 ---
38 arch/arm64/include/asm/module.h | 1 +
39 arch/arm64/include/asm/module.lds.h | 1 +
40 arch/arm64/kernel/ftrace.c | 13 ++++++++++---
41 arch/arm64/kernel/module-plts.c | 12 +++++++++++-
42 arch/arm64/kernel/module.c | 11 +++++++++++
43 5 files changed, 34 insertions(+), 4 deletions(-)
44
45 --- a/arch/arm64/include/asm/module.h
46 +++ b/arch/arm64/include/asm/module.h
47 @@ -19,6 +19,7 @@ struct mod_arch_specific {
48
49 /* for CONFIG_DYNAMIC_FTRACE */
50 struct plt_entry *ftrace_trampolines;
51 + struct plt_entry *init_ftrace_trampolines;
52 };
53
54 u64 module_emit_plt_entry(struct module *mod, Elf64_Shdr *sechdrs,
55 --- a/arch/arm64/include/asm/module.lds.h
56 +++ b/arch/arm64/include/asm/module.lds.h
57 @@ -2,6 +2,7 @@ SECTIONS {
58 .plt 0 : { BYTE(0) }
59 .init.plt 0 : { BYTE(0) }
60 .text.ftrace_trampoline 0 : { BYTE(0) }
61 + .init.text.ftrace_trampoline 0 : { BYTE(0) }
62
63 #ifdef CONFIG_KASAN_SW_TAGS
64 /*
65 --- a/arch/arm64/kernel/ftrace.c
66 +++ b/arch/arm64/kernel/ftrace.c
67 @@ -195,10 +195,17 @@ int ftrace_update_ftrace_func(ftrace_fun
68 return ftrace_modify_code(pc, 0, new, false);
69 }
70
71 -static struct plt_entry *get_ftrace_plt(struct module *mod)
72 +static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr)
73 {
74 #ifdef CONFIG_MODULES
75 - struct plt_entry *plt = mod->arch.ftrace_trampolines;
76 + struct plt_entry *plt = NULL;
77 +
78 + if (within_module_mem_type(addr, mod, MOD_INIT_TEXT))
79 + plt = mod->arch.init_ftrace_trampolines;
80 + else if (within_module_mem_type(addr, mod, MOD_TEXT))
81 + plt = mod->arch.ftrace_trampolines;
82 + else
83 + return NULL;
84
85 return &plt[FTRACE_PLT_IDX];
86 #else
87 @@ -270,7 +277,7 @@ static bool ftrace_find_callable_addr(st
88 if (WARN_ON(!mod))
89 return false;
90
91 - plt = get_ftrace_plt(mod);
92 + plt = get_ftrace_plt(mod, pc);
93 if (!plt) {
94 pr_err("ftrace: no module PLT for %ps\n", (void *)*addr);
95 return false;
96 --- a/arch/arm64/kernel/module-plts.c
97 +++ b/arch/arm64/kernel/module-plts.c
98 @@ -284,7 +284,7 @@ int module_frob_arch_sections(Elf_Ehdr *
99 unsigned long core_plts = 0;
100 unsigned long init_plts = 0;
101 Elf64_Sym *syms = NULL;
102 - Elf_Shdr *pltsec, *tramp = NULL;
103 + Elf_Shdr *pltsec, *tramp = NULL, *init_tramp = NULL;
104 int i;
105
106 /*
107 @@ -299,6 +299,9 @@ int module_frob_arch_sections(Elf_Ehdr *
108 else if (!strcmp(secstrings + sechdrs[i].sh_name,
109 ".text.ftrace_trampoline"))
110 tramp = sechdrs + i;
111 + else if (!strcmp(secstrings + sechdrs[i].sh_name,
112 + ".init.text.ftrace_trampoline"))
113 + init_tramp = sechdrs + i;
114 else if (sechdrs[i].sh_type == SHT_SYMTAB)
115 syms = (Elf64_Sym *)sechdrs[i].sh_addr;
116 }
117 @@ -364,5 +367,12 @@ int module_frob_arch_sections(Elf_Ehdr *
118 tramp->sh_size = NR_FTRACE_PLTS * sizeof(struct plt_entry);
119 }
120
121 + if (init_tramp) {
122 + init_tramp->sh_type = SHT_NOBITS;
123 + init_tramp->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
124 + init_tramp->sh_addralign = __alignof__(struct plt_entry);
125 + init_tramp->sh_size = NR_FTRACE_PLTS * sizeof(struct plt_entry);
126 + }
127 +
128 return 0;
129 }
130 --- a/arch/arm64/kernel/module.c
131 +++ b/arch/arm64/kernel/module.c
132 @@ -579,6 +579,17 @@ static int module_init_ftrace_plt(const
133 __init_plt(&plts[FTRACE_PLT_IDX], FTRACE_ADDR);
134
135 mod->arch.ftrace_trampolines = plts;
136 +
137 + s = find_section(hdr, sechdrs, ".init.text.ftrace_trampoline");
138 + if (!s)
139 + return -ENOEXEC;
140 +
141 + plts = (void *)s->sh_addr;
142 +
143 + __init_plt(&plts[FTRACE_PLT_IDX], FTRACE_ADDR);
144 +
145 + mod->arch.init_ftrace_trampolines = plts;
146 +
147 #endif
148 return 0;
149 }