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 if (memcmp(loc
, &zero
, size
)) {
150 pr_err("x86/modules: Invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n",
151 (int)ELF64_R_TYPE(rel
[i
].r_info
), loc
, val
);
154 write(loc
, &val
, size
);
156 if (memcmp(loc
, &val
, size
)) {
157 pr_warn("x86/modules: Invalid relocation target, existing value does not match expected value for type %d, loc %p, val %Lx\n",
158 (int)ELF64_R_TYPE(rel
[i
].r_info
), loc
, val
);
161 write(loc
, &zero
, size
);
167 pr_err("overflow in relocation type %d val %Lx\n",
168 (int)ELF64_R_TYPE(rel
[i
].r_info
), val
);
169 pr_err("`%s' likely not compiled with -mcmodel=kernel\n",
174 static int write_relocate_add(Elf64_Shdr
*sechdrs
,
176 unsigned int symindex
,
182 bool early
= me
->state
== MODULE_STATE_UNFORMED
;
183 void *(*write
)(void *, const void *, size_t) = memcpy
;
187 mutex_lock(&text_mutex
);
190 ret
= __write_relocate_add(sechdrs
, strtab
, symindex
, relsec
, me
,
195 mutex_unlock(&text_mutex
);
201 int apply_relocate_add(Elf64_Shdr
*sechdrs
,
203 unsigned int symindex
,
207 return write_relocate_add(sechdrs
, strtab
, symindex
, relsec
, me
, true);
210 #ifdef CONFIG_LIVEPATCH
211 void clear_relocate_add(Elf64_Shdr
*sechdrs
,
213 unsigned int symindex
,
217 write_relocate_add(sechdrs
, strtab
, symindex
, relsec
, me
, false);
223 int module_finalize(const Elf_Ehdr
*hdr
,
224 const Elf_Shdr
*sechdrs
,
227 const Elf_Shdr
*s
, *alt
= NULL
, *locks
= NULL
,
228 *orc
= NULL
, *orc_ip
= NULL
,
229 *retpolines
= NULL
, *returns
= NULL
, *ibt_endbr
= NULL
,
230 *calls
= NULL
, *cfi
= NULL
;
231 char *secstrings
= (void *)hdr
+ sechdrs
[hdr
->e_shstrndx
].sh_offset
;
233 for (s
= sechdrs
; s
< sechdrs
+ hdr
->e_shnum
; s
++) {
234 if (!strcmp(".altinstructions", secstrings
+ s
->sh_name
))
236 if (!strcmp(".smp_locks", secstrings
+ s
->sh_name
))
238 if (!strcmp(".orc_unwind", secstrings
+ s
->sh_name
))
240 if (!strcmp(".orc_unwind_ip", secstrings
+ s
->sh_name
))
242 if (!strcmp(".retpoline_sites", secstrings
+ s
->sh_name
))
244 if (!strcmp(".return_sites", secstrings
+ s
->sh_name
))
246 if (!strcmp(".call_sites", secstrings
+ s
->sh_name
))
248 if (!strcmp(".cfi_sites", secstrings
+ s
->sh_name
))
250 if (!strcmp(".ibt_endbr_seal", secstrings
+ s
->sh_name
))
254 if (retpolines
|| cfi
) {
255 void *rseg
= NULL
, *cseg
= NULL
;
256 unsigned int rsize
= 0, csize
= 0;
259 rseg
= (void *)retpolines
->sh_addr
;
260 rsize
= retpolines
->sh_size
;
264 cseg
= (void *)cfi
->sh_addr
;
265 csize
= cfi
->sh_size
;
268 apply_fineibt(rseg
, rseg
+ rsize
, cseg
, cseg
+ csize
);
271 void *rseg
= (void *)retpolines
->sh_addr
;
272 apply_retpolines(rseg
, rseg
+ retpolines
->sh_size
);
275 void *rseg
= (void *)returns
->sh_addr
;
276 apply_returns(rseg
, rseg
+ returns
->sh_size
);
279 /* patch .altinstructions */
280 void *aseg
= (void *)alt
->sh_addr
;
281 apply_alternatives(aseg
, aseg
+ alt
->sh_size
);
284 struct callthunk_sites cs
= {};
287 cs
.call_start
= (void *)calls
->sh_addr
;
288 cs
.call_end
= (void *)calls
->sh_addr
+ calls
->sh_size
;
292 cs
.alt_start
= (void *)alt
->sh_addr
;
293 cs
.alt_end
= (void *)alt
->sh_addr
+ alt
->sh_size
;
296 callthunks_patch_module_calls(&cs
, me
);
299 void *iseg
= (void *)ibt_endbr
->sh_addr
;
300 apply_seal_endbr(iseg
, iseg
+ ibt_endbr
->sh_size
);
303 void *lseg
= (void *)locks
->sh_addr
;
304 void *text
= me
->mem
[MOD_TEXT
].base
;
305 void *text_end
= text
+ me
->mem
[MOD_TEXT
].size
;
306 alternatives_smp_module_add(me
, me
->name
,
307 lseg
, lseg
+ locks
->sh_size
,
312 unwind_module_init(me
, (void *)orc_ip
->sh_addr
, orc_ip
->sh_size
,
313 (void *)orc
->sh_addr
, orc
->sh_size
);
318 void module_arch_cleanup(struct module
*mod
)
320 alternatives_smp_module_del(mod
);