11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
22d5bf28fSAmerigo Wang /* Kernel module help for x86.
32d5bf28fSAmerigo Wang Copyright (C) 2001 Rusty Russell.
42d5bf28fSAmerigo Wang
52d5bf28fSAmerigo Wang */
6c767a54bSJoe Perches
7c767a54bSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8c767a54bSJoe Perches
92d5bf28fSAmerigo Wang #include <linux/moduleloader.h>
102d5bf28fSAmerigo Wang #include <linux/elf.h>
112d5bf28fSAmerigo Wang #include <linux/vmalloc.h>
122d5bf28fSAmerigo Wang #include <linux/fs.h>
132d5bf28fSAmerigo Wang #include <linux/string.h>
142d5bf28fSAmerigo Wang #include <linux/kernel.h>
15bebf56a1SAndrey Ryabinin #include <linux/kasan.h>
162d5bf28fSAmerigo Wang #include <linux/bug.h>
172d5bf28fSAmerigo Wang #include <linux/mm.h>
185a0e3ad6STejun Heo #include <linux/gfp.h>
19d430d3d7SJason Baron #include <linux/jump_label.h>
20e2b32e67SKees Cook #include <linux/random.h>
215b384f93SJosh Poimboeuf #include <linux/memory.h>
2278c4374eSArd Biesheuvel #include <linux/stackprotector.h>
232d5bf28fSAmerigo Wang
2435de5b06SAndy Lutomirski #include <asm/text-patching.h>
252d5bf28fSAmerigo Wang #include <asm/page.h>
2678cac48cSBorislav Petkov #include <asm/setup.h>
27ee9f8fceSJosh Poimboeuf #include <asm/unwind.h>
282d5bf28fSAmerigo Wang
292d5bf28fSAmerigo Wang #if 0
30c767a54bSJoe Perches #define DEBUGP(fmt, ...) \
31c767a54bSJoe Perches printk(KERN_DEBUG fmt, ##__VA_ARGS__)
322d5bf28fSAmerigo Wang #else
33c767a54bSJoe Perches #define DEBUGP(fmt, ...) \
34c767a54bSJoe Perches do { \
35c767a54bSJoe Perches if (0) \
36c767a54bSJoe Perches printk(KERN_DEBUG fmt, ##__VA_ARGS__); \
37c767a54bSJoe Perches } while (0)
382d5bf28fSAmerigo Wang #endif
392d5bf28fSAmerigo Wang
400fdc83b9SAmerigo Wang #ifdef CONFIG_X86_32
apply_relocate(Elf32_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * me)410fdc83b9SAmerigo Wang int apply_relocate(Elf32_Shdr *sechdrs,
420fdc83b9SAmerigo Wang const char *strtab,
430fdc83b9SAmerigo Wang unsigned int symindex,
440fdc83b9SAmerigo Wang unsigned int relsec,
450fdc83b9SAmerigo Wang struct module *me)
460fdc83b9SAmerigo Wang {
470fdc83b9SAmerigo Wang unsigned int i;
480fdc83b9SAmerigo Wang Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
490fdc83b9SAmerigo Wang Elf32_Sym *sym;
500fdc83b9SAmerigo Wang uint32_t *location;
510fdc83b9SAmerigo Wang
52c767a54bSJoe Perches DEBUGP("Applying relocate section %u to %u\n",
53c767a54bSJoe Perches relsec, sechdrs[relsec].sh_info);
540fdc83b9SAmerigo Wang for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
550fdc83b9SAmerigo Wang /* This is where to make the change */
560fdc83b9SAmerigo Wang location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
570fdc83b9SAmerigo Wang + rel[i].r_offset;
580fdc83b9SAmerigo Wang /* This is the symbol it is referring to. Note that all
590fdc83b9SAmerigo Wang undefined symbols have been resolved. */
600fdc83b9SAmerigo Wang sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
610fdc83b9SAmerigo Wang + ELF32_R_SYM(rel[i].r_info);
620fdc83b9SAmerigo Wang
630fdc83b9SAmerigo Wang switch (ELF32_R_TYPE(rel[i].r_info)) {
640fdc83b9SAmerigo Wang case R_386_32:
650fdc83b9SAmerigo Wang /* We add the value into the location given */
660fdc83b9SAmerigo Wang *location += sym->st_value;
670fdc83b9SAmerigo Wang break;
680fdc83b9SAmerigo Wang case R_386_PC32:
69bb73d071SFangrui Song case R_386_PLT32:
702e76c283SGeert Uytterhoeven /* Add the value, subtract its position */
710fdc83b9SAmerigo Wang *location += sym->st_value - (uint32_t)location;
720fdc83b9SAmerigo Wang break;
730fdc83b9SAmerigo Wang default:
74c767a54bSJoe Perches pr_err("%s: Unknown relocation: %u\n",
750fdc83b9SAmerigo Wang me->name, ELF32_R_TYPE(rel[i].r_info));
760fdc83b9SAmerigo Wang return -ENOEXEC;
770fdc83b9SAmerigo Wang }
780fdc83b9SAmerigo Wang }
790fdc83b9SAmerigo Wang return 0;
800fdc83b9SAmerigo Wang }
810fdc83b9SAmerigo Wang #else /*X86_64*/
__write_relocate_add(Elf64_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * me,void * (* write)(void * dest,const void * src,size_t len),bool apply)820c05e7bdSSong Liu static int __write_relocate_add(Elf64_Shdr *sechdrs,
830fdc83b9SAmerigo Wang const char *strtab,
840fdc83b9SAmerigo Wang unsigned int symindex,
850fdc83b9SAmerigo Wang unsigned int relsec,
8688fc078aSPeter Zijlstra struct module *me,
870c05e7bdSSong Liu void *(*write)(void *dest, const void *src, size_t len),
880c05e7bdSSong Liu bool apply)
890fdc83b9SAmerigo Wang {
900fdc83b9SAmerigo Wang unsigned int i;
910fdc83b9SAmerigo Wang Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
920fdc83b9SAmerigo Wang Elf64_Sym *sym;
930fdc83b9SAmerigo Wang void *loc;
940fdc83b9SAmerigo Wang u64 val;
950c05e7bdSSong Liu u64 zero = 0ULL;
960fdc83b9SAmerigo Wang
970c05e7bdSSong Liu DEBUGP("%s relocate section %u to %u\n",
980c05e7bdSSong Liu apply ? "Applying" : "Clearing",
99c767a54bSJoe Perches relsec, sechdrs[relsec].sh_info);
1000fdc83b9SAmerigo Wang for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
1010c05e7bdSSong Liu size_t size;
1020c05e7bdSSong Liu
1030fdc83b9SAmerigo Wang /* This is where to make the change */
1040fdc83b9SAmerigo Wang loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
1050fdc83b9SAmerigo Wang + rel[i].r_offset;
1060fdc83b9SAmerigo Wang
1070fdc83b9SAmerigo Wang /* This is the symbol it is referring to. Note that all
1080fdc83b9SAmerigo Wang undefined symbols have been resolved. */
1090fdc83b9SAmerigo Wang sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
1100fdc83b9SAmerigo Wang + ELF64_R_SYM(rel[i].r_info);
1110fdc83b9SAmerigo Wang
1120fdc83b9SAmerigo Wang DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
1130fdc83b9SAmerigo Wang (int)ELF64_R_TYPE(rel[i].r_info),
1140fdc83b9SAmerigo Wang sym->st_value, rel[i].r_addend, (u64)loc);
1150fdc83b9SAmerigo Wang
1160fdc83b9SAmerigo Wang val = sym->st_value + rel[i].r_addend;
1170fdc83b9SAmerigo Wang
1180fdc83b9SAmerigo Wang switch (ELF64_R_TYPE(rel[i].r_info)) {
1190fdc83b9SAmerigo Wang case R_X86_64_NONE:
1200c05e7bdSSong Liu continue; /* nothing to write */
1210fdc83b9SAmerigo Wang case R_X86_64_64:
1220c05e7bdSSong Liu size = 8;
1230fdc83b9SAmerigo Wang break;
1240fdc83b9SAmerigo Wang case R_X86_64_32:
1250c05e7bdSSong Liu if (val != *(u32 *)&val)
1260fdc83b9SAmerigo Wang goto overflow;
1270c05e7bdSSong Liu size = 4;
1280fdc83b9SAmerigo Wang break;
1290fdc83b9SAmerigo Wang case R_X86_64_32S:
1300c05e7bdSSong Liu if ((s64)val != *(s32 *)&val)
1310fdc83b9SAmerigo Wang goto overflow;
1320c05e7bdSSong Liu size = 4;
1330fdc83b9SAmerigo Wang break;
13478c4374eSArd Biesheuvel #if defined(CONFIG_STACKPROTECTOR) && \
13578c4374eSArd Biesheuvel defined(CONFIG_CC_IS_CLANG) && CONFIG_CLANG_VERSION < 170000
13678c4374eSArd Biesheuvel case R_X86_64_REX_GOTPCRELX: {
13778c4374eSArd Biesheuvel static unsigned long __percpu *const addr = &__stack_chk_guard;
13878c4374eSArd Biesheuvel
13978c4374eSArd Biesheuvel if (sym->st_value != (u64)addr) {
14078c4374eSArd Biesheuvel pr_err("%s: Unsupported GOTPCREL relocation\n", me->name);
14178c4374eSArd Biesheuvel return -ENOEXEC;
14278c4374eSArd Biesheuvel }
14378c4374eSArd Biesheuvel
14478c4374eSArd Biesheuvel val = (u64)&addr + rel[i].r_addend;
14578c4374eSArd Biesheuvel fallthrough;
14678c4374eSArd Biesheuvel }
14778c4374eSArd Biesheuvel #endif
1480fdc83b9SAmerigo Wang case R_X86_64_PC32:
149b21ebf2fSH.J. Lu case R_X86_64_PLT32:
1500fdc83b9SAmerigo Wang val -= (u64)loc;
1510c05e7bdSSong Liu size = 4;
1520fdc83b9SAmerigo Wang break;
153b40a142bSArd Biesheuvel case R_X86_64_PC64:
154b40a142bSArd Biesheuvel val -= (u64)loc;
1550c05e7bdSSong Liu size = 8;
156b40a142bSArd Biesheuvel break;
1570fdc83b9SAmerigo Wang default:
158c767a54bSJoe Perches pr_err("%s: Unknown rela relocation: %llu\n",
1590fdc83b9SAmerigo Wang me->name, ELF64_R_TYPE(rel[i].r_info));
1600fdc83b9SAmerigo Wang return -ENOEXEC;
1610fdc83b9SAmerigo Wang }
1620fdc83b9SAmerigo Wang
1630c05e7bdSSong Liu if (apply) {
1641d7e707aSMike Rapoport (Microsoft) if (memcmp(loc, &zero, size)) {
1650c05e7bdSSong Liu pr_err("x86/modules: Invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n",
166eda9cec4SJosh Poimboeuf (int)ELF64_R_TYPE(rel[i].r_info), loc, val);
167eda9cec4SJosh Poimboeuf return -ENOEXEC;
1680c05e7bdSSong Liu }
1691d7e707aSMike Rapoport (Microsoft) write(loc, &val, size);
1700c05e7bdSSong Liu } else {
1710c05e7bdSSong Liu if (memcmp(loc, &val, size)) {
1720c05e7bdSSong Liu pr_warn("x86/modules: Invalid relocation target, existing value does not match expected value for type %d, loc %p, val %Lx\n",
1730c05e7bdSSong Liu (int)ELF64_R_TYPE(rel[i].r_info), loc, val);
1740c05e7bdSSong Liu return -ENOEXEC;
1750c05e7bdSSong Liu }
1760c05e7bdSSong Liu write(loc, &zero, size);
1770c05e7bdSSong Liu }
1780c05e7bdSSong Liu }
1790c05e7bdSSong Liu return 0;
180eda9cec4SJosh Poimboeuf
1810fdc83b9SAmerigo Wang overflow:
182c767a54bSJoe Perches pr_err("overflow in relocation type %d val %Lx\n",
1830fdc83b9SAmerigo Wang (int)ELF64_R_TYPE(rel[i].r_info), val);
184c767a54bSJoe Perches pr_err("`%s' likely not compiled with -mcmodel=kernel\n",
1850fdc83b9SAmerigo Wang me->name);
1860fdc83b9SAmerigo Wang return -ENOEXEC;
1870fdc83b9SAmerigo Wang }
18888fc078aSPeter Zijlstra
write_relocate_add(Elf64_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * me,bool apply)1890c05e7bdSSong Liu static int write_relocate_add(Elf64_Shdr *sechdrs,
19088fc078aSPeter Zijlstra const char *strtab,
19188fc078aSPeter Zijlstra unsigned int symindex,
19288fc078aSPeter Zijlstra unsigned int relsec,
1930c05e7bdSSong Liu struct module *me,
1940c05e7bdSSong Liu bool apply)
19588fc078aSPeter Zijlstra {
19688fc078aSPeter Zijlstra int ret;
19788fc078aSPeter Zijlstra bool early = me->state == MODULE_STATE_UNFORMED;
19888fc078aSPeter Zijlstra void *(*write)(void *, const void *, size_t) = memcpy;
19988fc078aSPeter Zijlstra
2005b384f93SJosh Poimboeuf if (!early) {
20188fc078aSPeter Zijlstra write = text_poke;
2025b384f93SJosh Poimboeuf mutex_lock(&text_mutex);
2035b384f93SJosh Poimboeuf }
20488fc078aSPeter Zijlstra
2050c05e7bdSSong Liu ret = __write_relocate_add(sechdrs, strtab, symindex, relsec, me,
2060c05e7bdSSong Liu write, apply);
20788fc078aSPeter Zijlstra
2085b384f93SJosh Poimboeuf if (!early) {
20988fc078aSPeter Zijlstra text_poke_sync();
2105b384f93SJosh Poimboeuf mutex_unlock(&text_mutex);
2115b384f93SJosh Poimboeuf }
21288fc078aSPeter Zijlstra
21388fc078aSPeter Zijlstra return ret;
21488fc078aSPeter Zijlstra }
21588fc078aSPeter Zijlstra
apply_relocate_add(Elf64_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * me)2160c05e7bdSSong Liu int apply_relocate_add(Elf64_Shdr *sechdrs,
2170c05e7bdSSong Liu const char *strtab,
2180c05e7bdSSong Liu unsigned int symindex,
2190c05e7bdSSong Liu unsigned int relsec,
2200c05e7bdSSong Liu struct module *me)
2210c05e7bdSSong Liu {
2220c05e7bdSSong Liu return write_relocate_add(sechdrs, strtab, symindex, relsec, me, true);
2230c05e7bdSSong Liu }
2240c05e7bdSSong Liu
2250c05e7bdSSong Liu #ifdef CONFIG_LIVEPATCH
clear_relocate_add(Elf64_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * me)2260c05e7bdSSong Liu void clear_relocate_add(Elf64_Shdr *sechdrs,
2270c05e7bdSSong Liu const char *strtab,
2280c05e7bdSSong Liu unsigned int symindex,
2290c05e7bdSSong Liu unsigned int relsec,
2300c05e7bdSSong Liu struct module *me)
2310c05e7bdSSong Liu {
2320c05e7bdSSong Liu write_relocate_add(sechdrs, strtab, symindex, relsec, me, false);
2330c05e7bdSSong Liu }
2340c05e7bdSSong Liu #endif
2350c05e7bdSSong Liu
2360fdc83b9SAmerigo Wang #endif
2370fdc83b9SAmerigo Wang
module_finalize(const Elf_Ehdr * hdr,const Elf_Shdr * sechdrs,struct module * me)2382d5bf28fSAmerigo Wang int module_finalize(const Elf_Ehdr *hdr,
2392d5bf28fSAmerigo Wang const Elf_Shdr *sechdrs,
2402d5bf28fSAmerigo Wang struct module *me)
2412d5bf28fSAmerigo Wang {
2421d7e707aSMike Rapoport (Microsoft) const Elf_Shdr *s, *alt = NULL, *locks = NULL,
24360bc276bSJuergen Gross *orc = NULL, *orc_ip = NULL,
244eaf44c81SThomas Gleixner *retpolines = NULL, *returns = NULL, *ibt_endbr = NULL,
245931ab636SPeter Zijlstra *calls = NULL, *cfi = NULL;
2462d5bf28fSAmerigo Wang char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
2472d5bf28fSAmerigo Wang
2482d5bf28fSAmerigo Wang for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
2492d5bf28fSAmerigo Wang if (!strcmp(".altinstructions", secstrings + s->sh_name))
2502d5bf28fSAmerigo Wang alt = s;
2511d7e707aSMike Rapoport (Microsoft) if (!strcmp(".smp_locks", secstrings + s->sh_name))
2521d7e707aSMike Rapoport (Microsoft) locks = s;
253ee9f8fceSJosh Poimboeuf if (!strcmp(".orc_unwind", secstrings + s->sh_name))
254ee9f8fceSJosh Poimboeuf orc = s;
255ee9f8fceSJosh Poimboeuf if (!strcmp(".orc_unwind_ip", secstrings + s->sh_name))
256ee9f8fceSJosh Poimboeuf orc_ip = s;
25775085009SPeter Zijlstra if (!strcmp(".retpoline_sites", secstrings + s->sh_name))
25875085009SPeter Zijlstra retpolines = s;
25915e67227SPeter Zijlstra if (!strcmp(".return_sites", secstrings + s->sh_name))
26015e67227SPeter Zijlstra returns = s;
261eaf44c81SThomas Gleixner if (!strcmp(".call_sites", secstrings + s->sh_name))
262eaf44c81SThomas Gleixner calls = s;
263931ab636SPeter Zijlstra if (!strcmp(".cfi_sites", secstrings + s->sh_name))
264931ab636SPeter Zijlstra cfi = s;
265ed53a0d9SPeter Zijlstra if (!strcmp(".ibt_endbr_seal", secstrings + s->sh_name))
266ed53a0d9SPeter Zijlstra ibt_endbr = s;
2672d5bf28fSAmerigo Wang }
2682d5bf28fSAmerigo Wang
269*872df34dSPeter Zijlstra its_init_mod(me);
270*872df34dSPeter Zijlstra
271931ab636SPeter Zijlstra if (retpolines || cfi) {
272931ab636SPeter Zijlstra void *rseg = NULL, *cseg = NULL;
273931ab636SPeter Zijlstra unsigned int rsize = 0, csize = 0;
274931ab636SPeter Zijlstra
275931ab636SPeter Zijlstra if (retpolines) {
276931ab636SPeter Zijlstra rseg = (void *)retpolines->sh_addr;
277931ab636SPeter Zijlstra rsize = retpolines->sh_size;
278931ab636SPeter Zijlstra }
279931ab636SPeter Zijlstra
280931ab636SPeter Zijlstra if (cfi) {
281931ab636SPeter Zijlstra cseg = (void *)cfi->sh_addr;
282931ab636SPeter Zijlstra csize = cfi->sh_size;
283931ab636SPeter Zijlstra }
284931ab636SPeter Zijlstra
2851d7e707aSMike Rapoport (Microsoft) apply_fineibt(rseg, rseg + rsize, cseg, cseg + csize);
286931ab636SPeter Zijlstra }
28775085009SPeter Zijlstra if (retpolines) {
28875085009SPeter Zijlstra void *rseg = (void *)retpolines->sh_addr;
2891d7e707aSMike Rapoport (Microsoft) apply_retpolines(rseg, rseg + retpolines->sh_size);
29075085009SPeter Zijlstra }
291*872df34dSPeter Zijlstra
292*872df34dSPeter Zijlstra its_fini_mod(me);
293*872df34dSPeter Zijlstra
29415e67227SPeter Zijlstra if (returns) {
29515e67227SPeter Zijlstra void *rseg = (void *)returns->sh_addr;
2961d7e707aSMike Rapoport (Microsoft) apply_returns(rseg, rseg + returns->sh_size);
29715e67227SPeter Zijlstra }
298ab9fea59SPeter Zijlstra if (calls) {
299eaf44c81SThomas Gleixner struct callthunk_sites cs = {};
300eaf44c81SThomas Gleixner
301eaf44c81SThomas Gleixner cs.call_start = (void *)calls->sh_addr;
302eaf44c81SThomas Gleixner cs.call_end = (void *)calls->sh_addr + calls->sh_size;
303eaf44c81SThomas Gleixner
304eaf44c81SThomas Gleixner callthunks_patch_module_calls(&cs, me);
305eaf44c81SThomas Gleixner }
306ab9fea59SPeter Zijlstra if (alt) {
307ab9fea59SPeter Zijlstra /* patch .altinstructions */
308ab9fea59SPeter Zijlstra void *aseg = (void *)alt->sh_addr;
309ab9fea59SPeter Zijlstra apply_alternatives(aseg, aseg + alt->sh_size);
310ab9fea59SPeter Zijlstra }
311ed53a0d9SPeter Zijlstra if (ibt_endbr) {
312ed53a0d9SPeter Zijlstra void *iseg = (void *)ibt_endbr->sh_addr;
3131d7e707aSMike Rapoport (Microsoft) apply_seal_endbr(iseg, iseg + ibt_endbr->sh_size);
314ed53a0d9SPeter Zijlstra }
315be84d8edSJulian Pidancet if (locks) {
3162d5bf28fSAmerigo Wang void *lseg = (void *)locks->sh_addr;
317ac3b4328SSong Liu void *text = me->mem[MOD_TEXT].base;
318ac3b4328SSong Liu void *text_end = text + me->mem[MOD_TEXT].size;
3192d5bf28fSAmerigo Wang alternatives_smp_module_add(me, me->name,
3202d5bf28fSAmerigo Wang lseg, lseg + locks->sh_size,
321be84d8edSJulian Pidancet text, text_end);
3222d5bf28fSAmerigo Wang }
3232d5bf28fSAmerigo Wang
3241d7e707aSMike Rapoport (Microsoft) if (orc && orc_ip)
3251d7e707aSMike Rapoport (Microsoft) unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size,
3261d7e707aSMike Rapoport (Microsoft) (void *)orc->sh_addr, orc->sh_size);
3271d7e707aSMike Rapoport (Microsoft)
3285336377dSLinus Torvalds return 0;
3292d5bf28fSAmerigo Wang }
3302d5bf28fSAmerigo Wang
module_arch_cleanup(struct module * mod)3312d5bf28fSAmerigo Wang void module_arch_cleanup(struct module *mod)
3322d5bf28fSAmerigo Wang {
3332d5bf28fSAmerigo Wang alternatives_smp_module_del(mod);
334*872df34dSPeter Zijlstra its_free_mod(mod);
3352d5bf28fSAmerigo Wang }
336