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> 222d5bf28fSAmerigo Wang 2335de5b06SAndy Lutomirski #include <asm/text-patching.h> 242d5bf28fSAmerigo Wang #include <asm/page.h> 2578cac48cSBorislav Petkov #include <asm/setup.h> 26ee9f8fceSJosh Poimboeuf #include <asm/unwind.h> 272d5bf28fSAmerigo Wang 282d5bf28fSAmerigo Wang #if 0 29c767a54bSJoe Perches #define DEBUGP(fmt, ...) \ 30c767a54bSJoe Perches printk(KERN_DEBUG fmt, ##__VA_ARGS__) 312d5bf28fSAmerigo Wang #else 32c767a54bSJoe Perches #define DEBUGP(fmt, ...) \ 33c767a54bSJoe Perches do { \ 34c767a54bSJoe Perches if (0) \ 35c767a54bSJoe Perches printk(KERN_DEBUG fmt, ##__VA_ARGS__); \ 36c767a54bSJoe Perches } while (0) 372d5bf28fSAmerigo Wang #endif 382d5bf28fSAmerigo Wang 39e2b32e67SKees Cook #ifdef CONFIG_RANDOMIZE_BASE 40e2b32e67SKees Cook static unsigned long module_load_offset; 41e2b32e67SKees Cook 429dd721c6SKees Cook /* Mutex protects the module_load_offset. */ 439dd721c6SKees Cook static DEFINE_MUTEX(module_kaslr_mutex); 449dd721c6SKees Cook 45e2b32e67SKees Cook static unsigned long int get_module_load_offset(void) 46e2b32e67SKees Cook { 4778cac48cSBorislav Petkov if (kaslr_enabled()) { 489dd721c6SKees Cook mutex_lock(&module_kaslr_mutex); 49e2b32e67SKees Cook /* 50e2b32e67SKees Cook * Calculate the module_load_offset the first time this 51e2b32e67SKees Cook * code is called. Once calculated it stays the same until 52e2b32e67SKees Cook * reboot. 53e2b32e67SKees Cook */ 54e2b32e67SKees Cook if (module_load_offset == 0) 55e2b32e67SKees Cook module_load_offset = 56e2b32e67SKees Cook (get_random_int() % 1024 + 1) * PAGE_SIZE; 579dd721c6SKees Cook mutex_unlock(&module_kaslr_mutex); 58e2b32e67SKees Cook } 59e2b32e67SKees Cook return module_load_offset; 60e2b32e67SKees Cook } 61e2b32e67SKees Cook #else 62e2b32e67SKees Cook static unsigned long int get_module_load_offset(void) 63e2b32e67SKees Cook { 64e2b32e67SKees Cook return 0; 65e2b32e67SKees Cook } 66e2b32e67SKees Cook #endif 67e2b32e67SKees Cook 680fdc83b9SAmerigo Wang void *module_alloc(unsigned long size) 690fdc83b9SAmerigo Wang { 70bebf56a1SAndrey Ryabinin void *p; 71bebf56a1SAndrey Ryabinin 72d0a21265SDavid Rientjes if (PAGE_ALIGN(size) > MODULES_LEN) 730fdc83b9SAmerigo Wang return NULL; 74bebf56a1SAndrey Ryabinin 75bebf56a1SAndrey Ryabinin p = __vmalloc_node_range(size, MODULE_ALIGN, 76e2b32e67SKees Cook MODULES_VADDR + get_module_load_offset(), 7719809c2dSMichal Hocko MODULES_END, GFP_KERNEL, 78f2c65fb3SNadav Amit PAGE_KERNEL, 0, NUMA_NO_NODE, 79e2b32e67SKees Cook __builtin_return_address(0)); 80bebf56a1SAndrey Ryabinin if (p && (kasan_module_alloc(p, size) < 0)) { 81bebf56a1SAndrey Ryabinin vfree(p); 82bebf56a1SAndrey Ryabinin return NULL; 83bebf56a1SAndrey Ryabinin } 84bebf56a1SAndrey Ryabinin 85bebf56a1SAndrey Ryabinin return p; 860fdc83b9SAmerigo Wang } 870fdc83b9SAmerigo Wang 880fdc83b9SAmerigo Wang #ifdef CONFIG_X86_32 890fdc83b9SAmerigo Wang int apply_relocate(Elf32_Shdr *sechdrs, 900fdc83b9SAmerigo Wang const char *strtab, 910fdc83b9SAmerigo Wang unsigned int symindex, 920fdc83b9SAmerigo Wang unsigned int relsec, 930fdc83b9SAmerigo Wang struct module *me) 940fdc83b9SAmerigo Wang { 950fdc83b9SAmerigo Wang unsigned int i; 960fdc83b9SAmerigo Wang Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; 970fdc83b9SAmerigo Wang Elf32_Sym *sym; 980fdc83b9SAmerigo Wang uint32_t *location; 990fdc83b9SAmerigo Wang 100c767a54bSJoe Perches DEBUGP("Applying relocate section %u to %u\n", 101c767a54bSJoe Perches relsec, sechdrs[relsec].sh_info); 1020fdc83b9SAmerigo Wang for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 1030fdc83b9SAmerigo Wang /* This is where to make the change */ 1040fdc83b9SAmerigo Wang location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 1050fdc83b9SAmerigo Wang + rel[i].r_offset; 1060fdc83b9SAmerigo Wang /* This is the symbol it is referring to. Note that all 1070fdc83b9SAmerigo Wang undefined symbols have been resolved. */ 1080fdc83b9SAmerigo Wang sym = (Elf32_Sym *)sechdrs[symindex].sh_addr 1090fdc83b9SAmerigo Wang + ELF32_R_SYM(rel[i].r_info); 1100fdc83b9SAmerigo Wang 1110fdc83b9SAmerigo Wang switch (ELF32_R_TYPE(rel[i].r_info)) { 1120fdc83b9SAmerigo Wang case R_386_32: 1130fdc83b9SAmerigo Wang /* We add the value into the location given */ 1140fdc83b9SAmerigo Wang *location += sym->st_value; 1150fdc83b9SAmerigo Wang break; 1160fdc83b9SAmerigo Wang case R_386_PC32: 117bb73d071SFangrui Song case R_386_PLT32: 1182e76c283SGeert Uytterhoeven /* Add the value, subtract its position */ 1190fdc83b9SAmerigo Wang *location += sym->st_value - (uint32_t)location; 1200fdc83b9SAmerigo Wang break; 1210fdc83b9SAmerigo Wang default: 122c767a54bSJoe Perches pr_err("%s: Unknown relocation: %u\n", 1230fdc83b9SAmerigo Wang me->name, ELF32_R_TYPE(rel[i].r_info)); 1240fdc83b9SAmerigo Wang return -ENOEXEC; 1250fdc83b9SAmerigo Wang } 1260fdc83b9SAmerigo Wang } 1270fdc83b9SAmerigo Wang return 0; 1280fdc83b9SAmerigo Wang } 1290fdc83b9SAmerigo Wang #else /*X86_64*/ 13088fc078aSPeter Zijlstra static int __apply_relocate_add(Elf64_Shdr *sechdrs, 1310fdc83b9SAmerigo Wang const char *strtab, 1320fdc83b9SAmerigo Wang unsigned int symindex, 1330fdc83b9SAmerigo Wang unsigned int relsec, 13488fc078aSPeter Zijlstra struct module *me, 13588fc078aSPeter Zijlstra void *(*write)(void *dest, const void *src, size_t len)) 1360fdc83b9SAmerigo Wang { 1370fdc83b9SAmerigo Wang unsigned int i; 1380fdc83b9SAmerigo Wang Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; 1390fdc83b9SAmerigo Wang Elf64_Sym *sym; 1400fdc83b9SAmerigo Wang void *loc; 1410fdc83b9SAmerigo Wang u64 val; 1420fdc83b9SAmerigo Wang 143c767a54bSJoe Perches DEBUGP("Applying relocate section %u to %u\n", 144c767a54bSJoe Perches relsec, sechdrs[relsec].sh_info); 1450fdc83b9SAmerigo Wang for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 1460fdc83b9SAmerigo Wang /* This is where to make the change */ 1470fdc83b9SAmerigo Wang loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 1480fdc83b9SAmerigo Wang + rel[i].r_offset; 1490fdc83b9SAmerigo Wang 1500fdc83b9SAmerigo Wang /* This is the symbol it is referring to. Note that all 1510fdc83b9SAmerigo Wang undefined symbols have been resolved. */ 1520fdc83b9SAmerigo Wang sym = (Elf64_Sym *)sechdrs[symindex].sh_addr 1530fdc83b9SAmerigo Wang + ELF64_R_SYM(rel[i].r_info); 1540fdc83b9SAmerigo Wang 1550fdc83b9SAmerigo Wang DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n", 1560fdc83b9SAmerigo Wang (int)ELF64_R_TYPE(rel[i].r_info), 1570fdc83b9SAmerigo Wang sym->st_value, rel[i].r_addend, (u64)loc); 1580fdc83b9SAmerigo Wang 1590fdc83b9SAmerigo Wang val = sym->st_value + rel[i].r_addend; 1600fdc83b9SAmerigo Wang 1610fdc83b9SAmerigo Wang switch (ELF64_R_TYPE(rel[i].r_info)) { 1620fdc83b9SAmerigo Wang case R_X86_64_NONE: 1630fdc83b9SAmerigo Wang break; 1640fdc83b9SAmerigo Wang case R_X86_64_64: 165eda9cec4SJosh Poimboeuf if (*(u64 *)loc != 0) 166eda9cec4SJosh Poimboeuf goto invalid_relocation; 16788fc078aSPeter Zijlstra write(loc, &val, 8); 1680fdc83b9SAmerigo Wang break; 1690fdc83b9SAmerigo Wang case R_X86_64_32: 170eda9cec4SJosh Poimboeuf if (*(u32 *)loc != 0) 171eda9cec4SJosh Poimboeuf goto invalid_relocation; 17288fc078aSPeter Zijlstra write(loc, &val, 4); 1730fdc83b9SAmerigo Wang if (val != *(u32 *)loc) 1740fdc83b9SAmerigo Wang goto overflow; 1750fdc83b9SAmerigo Wang break; 1760fdc83b9SAmerigo Wang case R_X86_64_32S: 177eda9cec4SJosh Poimboeuf if (*(s32 *)loc != 0) 178eda9cec4SJosh Poimboeuf goto invalid_relocation; 17988fc078aSPeter Zijlstra write(loc, &val, 4); 1800fdc83b9SAmerigo Wang if ((s64)val != *(s32 *)loc) 1810fdc83b9SAmerigo Wang goto overflow; 1820fdc83b9SAmerigo Wang break; 1830fdc83b9SAmerigo Wang case R_X86_64_PC32: 184b21ebf2fSH.J. Lu case R_X86_64_PLT32: 185eda9cec4SJosh Poimboeuf if (*(u32 *)loc != 0) 186eda9cec4SJosh Poimboeuf goto invalid_relocation; 1870fdc83b9SAmerigo Wang val -= (u64)loc; 18888fc078aSPeter Zijlstra write(loc, &val, 4); 1890fdc83b9SAmerigo Wang #if 0 1900fdc83b9SAmerigo Wang if ((s64)val != *(s32 *)loc) 1910fdc83b9SAmerigo Wang goto overflow; 1920fdc83b9SAmerigo Wang #endif 1930fdc83b9SAmerigo Wang break; 194b40a142bSArd Biesheuvel case R_X86_64_PC64: 195b40a142bSArd Biesheuvel if (*(u64 *)loc != 0) 196b40a142bSArd Biesheuvel goto invalid_relocation; 197b40a142bSArd Biesheuvel val -= (u64)loc; 19888fc078aSPeter Zijlstra write(loc, &val, 8); 199b40a142bSArd Biesheuvel break; 2000fdc83b9SAmerigo Wang default: 201c767a54bSJoe Perches pr_err("%s: Unknown rela relocation: %llu\n", 2020fdc83b9SAmerigo Wang me->name, ELF64_R_TYPE(rel[i].r_info)); 2030fdc83b9SAmerigo Wang return -ENOEXEC; 2040fdc83b9SAmerigo Wang } 2050fdc83b9SAmerigo Wang } 2060fdc83b9SAmerigo Wang return 0; 2070fdc83b9SAmerigo Wang 208eda9cec4SJosh Poimboeuf invalid_relocation: 209eda9cec4SJosh Poimboeuf pr_err("x86/modules: Skipping invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n", 210eda9cec4SJosh Poimboeuf (int)ELF64_R_TYPE(rel[i].r_info), loc, val); 211eda9cec4SJosh Poimboeuf return -ENOEXEC; 212eda9cec4SJosh Poimboeuf 2130fdc83b9SAmerigo Wang overflow: 214c767a54bSJoe Perches pr_err("overflow in relocation type %d val %Lx\n", 2150fdc83b9SAmerigo Wang (int)ELF64_R_TYPE(rel[i].r_info), val); 216c767a54bSJoe Perches pr_err("`%s' likely not compiled with -mcmodel=kernel\n", 2170fdc83b9SAmerigo Wang me->name); 2180fdc83b9SAmerigo Wang return -ENOEXEC; 2190fdc83b9SAmerigo Wang } 22088fc078aSPeter Zijlstra 22188fc078aSPeter Zijlstra int apply_relocate_add(Elf64_Shdr *sechdrs, 22288fc078aSPeter Zijlstra const char *strtab, 22388fc078aSPeter Zijlstra unsigned int symindex, 22488fc078aSPeter Zijlstra unsigned int relsec, 22588fc078aSPeter Zijlstra struct module *me) 22688fc078aSPeter Zijlstra { 22788fc078aSPeter Zijlstra int ret; 22888fc078aSPeter Zijlstra bool early = me->state == MODULE_STATE_UNFORMED; 22988fc078aSPeter Zijlstra void *(*write)(void *, const void *, size_t) = memcpy; 23088fc078aSPeter Zijlstra 2315b384f93SJosh Poimboeuf if (!early) { 23288fc078aSPeter Zijlstra write = text_poke; 2335b384f93SJosh Poimboeuf mutex_lock(&text_mutex); 2345b384f93SJosh Poimboeuf } 23588fc078aSPeter Zijlstra 23688fc078aSPeter Zijlstra ret = __apply_relocate_add(sechdrs, strtab, symindex, relsec, me, 23788fc078aSPeter Zijlstra write); 23888fc078aSPeter Zijlstra 2395b384f93SJosh Poimboeuf if (!early) { 24088fc078aSPeter Zijlstra text_poke_sync(); 2415b384f93SJosh Poimboeuf mutex_unlock(&text_mutex); 2425b384f93SJosh Poimboeuf } 24388fc078aSPeter Zijlstra 24488fc078aSPeter Zijlstra return ret; 24588fc078aSPeter Zijlstra } 24688fc078aSPeter Zijlstra 2470fdc83b9SAmerigo Wang #endif 2480fdc83b9SAmerigo Wang 2492d5bf28fSAmerigo Wang int module_finalize(const Elf_Ehdr *hdr, 2502d5bf28fSAmerigo Wang const Elf_Shdr *sechdrs, 2512d5bf28fSAmerigo Wang struct module *me) 2522d5bf28fSAmerigo Wang { 2532d5bf28fSAmerigo Wang const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL, 254*75085009SPeter Zijlstra *para = NULL, *orc = NULL, *orc_ip = NULL, 255*75085009SPeter Zijlstra *retpolines = NULL; 2562d5bf28fSAmerigo Wang char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 2572d5bf28fSAmerigo Wang 2582d5bf28fSAmerigo Wang for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { 2592d5bf28fSAmerigo Wang if (!strcmp(".text", secstrings + s->sh_name)) 2602d5bf28fSAmerigo Wang text = s; 2612d5bf28fSAmerigo Wang if (!strcmp(".altinstructions", secstrings + s->sh_name)) 2622d5bf28fSAmerigo Wang alt = s; 2632d5bf28fSAmerigo Wang if (!strcmp(".smp_locks", secstrings + s->sh_name)) 2642d5bf28fSAmerigo Wang locks = s; 2652d5bf28fSAmerigo Wang if (!strcmp(".parainstructions", secstrings + s->sh_name)) 2662d5bf28fSAmerigo Wang para = s; 267ee9f8fceSJosh Poimboeuf if (!strcmp(".orc_unwind", secstrings + s->sh_name)) 268ee9f8fceSJosh Poimboeuf orc = s; 269ee9f8fceSJosh Poimboeuf if (!strcmp(".orc_unwind_ip", secstrings + s->sh_name)) 270ee9f8fceSJosh Poimboeuf orc_ip = s; 271*75085009SPeter Zijlstra if (!strcmp(".retpoline_sites", secstrings + s->sh_name)) 272*75085009SPeter Zijlstra retpolines = s; 2732d5bf28fSAmerigo Wang } 2742d5bf28fSAmerigo Wang 275*75085009SPeter Zijlstra if (retpolines) { 276*75085009SPeter Zijlstra void *rseg = (void *)retpolines->sh_addr; 277*75085009SPeter Zijlstra apply_retpolines(rseg, rseg + retpolines->sh_size); 278*75085009SPeter Zijlstra } 2792d5bf28fSAmerigo Wang if (alt) { 2802d5bf28fSAmerigo Wang /* patch .altinstructions */ 2812d5bf28fSAmerigo Wang void *aseg = (void *)alt->sh_addr; 2822d5bf28fSAmerigo Wang apply_alternatives(aseg, aseg + alt->sh_size); 2832d5bf28fSAmerigo Wang } 2842d5bf28fSAmerigo Wang if (locks && text) { 2852d5bf28fSAmerigo Wang void *lseg = (void *)locks->sh_addr; 2862d5bf28fSAmerigo Wang void *tseg = (void *)text->sh_addr; 2872d5bf28fSAmerigo Wang alternatives_smp_module_add(me, me->name, 2882d5bf28fSAmerigo Wang lseg, lseg + locks->sh_size, 2892d5bf28fSAmerigo Wang tseg, tseg + text->sh_size); 2902d5bf28fSAmerigo Wang } 2912d5bf28fSAmerigo Wang 2922d5bf28fSAmerigo Wang if (para) { 2932d5bf28fSAmerigo Wang void *pseg = (void *)para->sh_addr; 2942d5bf28fSAmerigo Wang apply_paravirt(pseg, pseg + para->sh_size); 2952d5bf28fSAmerigo Wang } 2962d5bf28fSAmerigo Wang 297d9f5ab7bSJason Baron /* make jump label nops */ 298d9f5ab7bSJason Baron jump_label_apply_nops(me); 299d9f5ab7bSJason Baron 300ee9f8fceSJosh Poimboeuf if (orc && orc_ip) 301ee9f8fceSJosh Poimboeuf unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size, 302ee9f8fceSJosh Poimboeuf (void *)orc->sh_addr, orc->sh_size); 303ee9f8fceSJosh Poimboeuf 3045336377dSLinus Torvalds return 0; 3052d5bf28fSAmerigo Wang } 3062d5bf28fSAmerigo Wang 3072d5bf28fSAmerigo Wang void module_arch_cleanup(struct module *mod) 3082d5bf28fSAmerigo Wang { 3092d5bf28fSAmerigo Wang alternatives_smp_module_del(mod); 3102d5bf28fSAmerigo Wang } 311