1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Kernel module help for x86.
3 Copyright (C) 2001 Rusty Russell.
7 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9 #include <linux/moduleloader.h>
10 #include <linux/elf.h>
11 #include <linux/vmalloc.h>
13 #include <linux/string.h>
14 #include <linux/kernel.h>
15 #include <linux/kasan.h>
16 #include <linux/bug.h>
18 #include <linux/gfp.h>
19 #include <linux/jump_label.h>
20 #include <linux/random.h>
21 #include <linux/memory.h>
23 #include <asm/text-patching.h>
25 #include <asm/setup.h>
26 #include <asm/unwind.h>
29 #define DEBUGP(fmt, ...) \
30 printk(KERN_DEBUG fmt, ##__VA_ARGS__)
32 #define DEBUGP(fmt, ...) \
35 printk(KERN_DEBUG fmt, ##__VA_ARGS__); \
40 int apply_relocate(Elf32_Shdr
*sechdrs
,
42 unsigned int symindex
,
47 Elf32_Rel
*rel
= (void *)sechdrs
[relsec
].sh_addr
;
51 DEBUGP("Applying relocate section %u to %u\n",
52 relsec
, sechdrs
[relsec
].sh_info
);
53 for (i
= 0; i
< sechdrs
[relsec
].sh_size
/ sizeof(*rel
); i
++) {
54 /* This is where to make the change */
55 location
= (void *)sechdrs
[sechdrs
[relsec
].sh_info
].sh_addr
57 /* This is the symbol it is referring to. Note that all
58 undefined symbols have been resolved. */
59 sym
= (Elf32_Sym
*)sechdrs
[symindex
].sh_addr
60 + ELF32_R_SYM(rel
[i
].r_info
);
62 switch (ELF32_R_TYPE(rel
[i
].r_info
)) {
64 /* We add the value into the location given */
65 *location
+= sym
->st_value
;
69 /* Add the value, subtract its position */
70 *location
+= sym
->st_value
- (uint32_t)location
;
73 pr_err("%s: Unknown relocation: %u\n",
74 me
->name
, ELF32_R_TYPE(rel
[i
].r_info
));
81 static int __write_relocate_add(Elf64_Shdr
*sechdrs
,
83 unsigned int symindex
,
86 void *(*write
)(void *dest
, const void *src
, size_t len
),
90 Elf64_Rela
*rel
= (void *)sechdrs
[relsec
].sh_addr
;
96 DEBUGP("%s relocate section %u to %u\n",
97 apply
? "Applying" : "Clearing",
98 relsec
, sechdrs
[relsec
].sh_info
);
99 for (i
= 0; i
< sechdrs
[relsec
].sh_size
/ sizeof(*rel
); i
++) {
102 /* This is where to make the change */
103 loc
= (void *)sechdrs
[sechdrs
[relsec
].sh_info
].sh_addr
106 /* This is the symbol it is referring to. Note that all
107 undefined symbols have been resolved. */
108 sym
= (Elf64_Sym
*)sechdrs
[symindex
].sh_addr
109 + ELF64_R_SYM(rel
[i
].r_info
);
111 DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
112 (int)ELF64_R_TYPE(rel
[i
].r_info
),
113 sym
->st_value
, rel
[i
].r_addend
, (u64
)loc
);
115 val
= sym
->st_value
+ rel
[i
].r_addend
;
117 switch (ELF64_R_TYPE(rel
[i
].r_info
)) {
119 continue; /* nothing to write */
124 if (val
!= *(u32
*)&val
)
129 if ((s64
)val
!= *(s32
*)&val
)
143 pr_err("%s: Unknown rela relocation: %llu\n",
144 me
->name
, ELF64_R_TYPE(rel
[i
].r_info
));
149 void *wr_loc
= module_writable_address(me
, loc
);
151 if (memcmp(wr_loc
, &zero
, size
)) {
152 pr_err("x86/modules: Invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n",
153 (int)ELF64_R_TYPE(rel
[i
].r_info
), loc
, val
);
156 write(wr_loc
, &val
, size
);
158 if (memcmp(loc
, &val
, size
)) {
159 pr_warn("x86/modules: Invalid relocation target, existing value does not match expected value for type %d, loc %p, val %Lx\n",
160 (int)ELF64_R_TYPE(rel
[i
].r_info
), loc
, val
);
163 /* FIXME: needs care for ROX module allocations */
164 write(loc
, &zero
, size
);
170 pr_err("overflow in relocation type %d val %Lx\n",
171 (int)ELF64_R_TYPE(rel
[i
].r_info
), val
);
172 pr_err("`%s' likely not compiled with -mcmodel=kernel\n",
177 static int write_relocate_add(Elf64_Shdr
*sechdrs
,
179 unsigned int symindex
,
185 bool early
= me
->state
== MODULE_STATE_UNFORMED
;
186 void *(*write
)(void *, const void *, size_t) = memcpy
;
190 mutex_lock(&text_mutex
);
193 ret
= __write_relocate_add(sechdrs
, strtab
, symindex
, relsec
, me
,
198 mutex_unlock(&text_mutex
);
204 int apply_relocate_add(Elf64_Shdr
*sechdrs
,
206 unsigned int symindex
,
210 return write_relocate_add(sechdrs
, strtab
, symindex
, relsec
, me
, true);
213 #ifdef CONFIG_LIVEPATCH
214 void clear_relocate_add(Elf64_Shdr
*sechdrs
,
216 unsigned int symindex
,
220 write_relocate_add(sechdrs
, strtab
, symindex
, relsec
, me
, false);
226 int module_finalize(const Elf_Ehdr
*hdr
,
227 const Elf_Shdr
*sechdrs
,
230 const Elf_Shdr
*s
, *alt
= NULL
,
231 *orc
= NULL
, *orc_ip
= NULL
,
232 *retpolines
= NULL
, *returns
= NULL
, *ibt_endbr
= NULL
,
233 *calls
= NULL
, *cfi
= NULL
;
234 char *secstrings
= (void *)hdr
+ sechdrs
[hdr
->e_shstrndx
].sh_offset
;
236 for (s
= sechdrs
; s
< sechdrs
+ hdr
->e_shnum
; s
++) {
237 if (!strcmp(".altinstructions", secstrings
+ s
->sh_name
))
239 if (!strcmp(".orc_unwind", secstrings
+ s
->sh_name
))
241 if (!strcmp(".orc_unwind_ip", secstrings
+ s
->sh_name
))
243 if (!strcmp(".retpoline_sites", secstrings
+ s
->sh_name
))
245 if (!strcmp(".return_sites", secstrings
+ s
->sh_name
))
247 if (!strcmp(".call_sites", secstrings
+ s
->sh_name
))
249 if (!strcmp(".cfi_sites", secstrings
+ s
->sh_name
))
251 if (!strcmp(".ibt_endbr_seal", secstrings
+ s
->sh_name
))
255 if (retpolines
|| cfi
) {
256 void *rseg
= NULL
, *cseg
= NULL
;
257 unsigned int rsize
= 0, csize
= 0;
260 rseg
= (void *)retpolines
->sh_addr
;
261 rsize
= retpolines
->sh_size
;
265 cseg
= (void *)cfi
->sh_addr
;
266 csize
= cfi
->sh_size
;
269 apply_fineibt(rseg
, rseg
+ rsize
, cseg
, cseg
+ csize
, me
);
272 void *rseg
= (void *)retpolines
->sh_addr
;
273 apply_retpolines(rseg
, rseg
+ retpolines
->sh_size
, me
);
276 void *rseg
= (void *)returns
->sh_addr
;
277 apply_returns(rseg
, rseg
+ returns
->sh_size
, me
);
280 /* patch .altinstructions */
281 void *aseg
= (void *)alt
->sh_addr
;
282 apply_alternatives(aseg
, aseg
+ alt
->sh_size
, me
);
285 struct callthunk_sites cs
= {};
288 cs
.call_start
= (void *)calls
->sh_addr
;
289 cs
.call_end
= (void *)calls
->sh_addr
+ calls
->sh_size
;
293 cs
.alt_start
= (void *)alt
->sh_addr
;
294 cs
.alt_end
= (void *)alt
->sh_addr
+ alt
->sh_size
;
297 callthunks_patch_module_calls(&cs
, me
);
300 void *iseg
= (void *)ibt_endbr
->sh_addr
;
301 apply_seal_endbr(iseg
, iseg
+ ibt_endbr
->sh_size
, me
);
305 unwind_module_init(me
, (void *)orc_ip
->sh_addr
, orc_ip
->sh_size
,
306 (void *)orc
->sh_addr
, orc
->sh_size
);
311 int module_post_finalize(const Elf_Ehdr
*hdr
,
312 const Elf_Shdr
*sechdrs
,
315 const Elf_Shdr
*s
, *locks
= NULL
;
316 char *secstrings
= (void *)hdr
+ sechdrs
[hdr
->e_shstrndx
].sh_offset
;
318 for (s
= sechdrs
; s
< sechdrs
+ hdr
->e_shnum
; s
++) {
319 if (!strcmp(".smp_locks", secstrings
+ s
->sh_name
))
324 void *lseg
= (void *)locks
->sh_addr
;
325 void *text
= me
->mem
[MOD_TEXT
].base
;
326 void *text_end
= text
+ me
->mem
[MOD_TEXT
].size
;
327 alternatives_smp_module_add(me
, me
->name
,
328 lseg
, lseg
+ locks
->sh_size
,
335 void module_arch_cleanup(struct module
*mod
)
337 alternatives_smp_module_del(mod
);