1*1a59d1b8SThomas 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> 212d5bf28fSAmerigo Wang 2235de5b06SAndy Lutomirski #include <asm/text-patching.h> 232d5bf28fSAmerigo Wang #include <asm/page.h> 242d5bf28fSAmerigo Wang #include <asm/pgtable.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: 1172e76c283SGeert Uytterhoeven /* Add the value, subtract its position */ 1180fdc83b9SAmerigo Wang *location += sym->st_value - (uint32_t)location; 1190fdc83b9SAmerigo Wang break; 1200fdc83b9SAmerigo Wang default: 121c767a54bSJoe Perches pr_err("%s: Unknown relocation: %u\n", 1220fdc83b9SAmerigo Wang me->name, ELF32_R_TYPE(rel[i].r_info)); 1230fdc83b9SAmerigo Wang return -ENOEXEC; 1240fdc83b9SAmerigo Wang } 1250fdc83b9SAmerigo Wang } 1260fdc83b9SAmerigo Wang return 0; 1270fdc83b9SAmerigo Wang } 1280fdc83b9SAmerigo Wang #else /*X86_64*/ 1290fdc83b9SAmerigo Wang int apply_relocate_add(Elf64_Shdr *sechdrs, 1300fdc83b9SAmerigo Wang const char *strtab, 1310fdc83b9SAmerigo Wang unsigned int symindex, 1320fdc83b9SAmerigo Wang unsigned int relsec, 1330fdc83b9SAmerigo Wang struct module *me) 1340fdc83b9SAmerigo Wang { 1350fdc83b9SAmerigo Wang unsigned int i; 1360fdc83b9SAmerigo Wang Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; 1370fdc83b9SAmerigo Wang Elf64_Sym *sym; 1380fdc83b9SAmerigo Wang void *loc; 1390fdc83b9SAmerigo Wang u64 val; 1400fdc83b9SAmerigo Wang 141c767a54bSJoe Perches DEBUGP("Applying relocate section %u to %u\n", 142c767a54bSJoe Perches relsec, sechdrs[relsec].sh_info); 1430fdc83b9SAmerigo Wang for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 1440fdc83b9SAmerigo Wang /* This is where to make the change */ 1450fdc83b9SAmerigo Wang loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 1460fdc83b9SAmerigo Wang + rel[i].r_offset; 1470fdc83b9SAmerigo Wang 1480fdc83b9SAmerigo Wang /* This is the symbol it is referring to. Note that all 1490fdc83b9SAmerigo Wang undefined symbols have been resolved. */ 1500fdc83b9SAmerigo Wang sym = (Elf64_Sym *)sechdrs[symindex].sh_addr 1510fdc83b9SAmerigo Wang + ELF64_R_SYM(rel[i].r_info); 1520fdc83b9SAmerigo Wang 1530fdc83b9SAmerigo Wang DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n", 1540fdc83b9SAmerigo Wang (int)ELF64_R_TYPE(rel[i].r_info), 1550fdc83b9SAmerigo Wang sym->st_value, rel[i].r_addend, (u64)loc); 1560fdc83b9SAmerigo Wang 1570fdc83b9SAmerigo Wang val = sym->st_value + rel[i].r_addend; 1580fdc83b9SAmerigo Wang 1590fdc83b9SAmerigo Wang switch (ELF64_R_TYPE(rel[i].r_info)) { 1600fdc83b9SAmerigo Wang case R_X86_64_NONE: 1610fdc83b9SAmerigo Wang break; 1620fdc83b9SAmerigo Wang case R_X86_64_64: 163eda9cec4SJosh Poimboeuf if (*(u64 *)loc != 0) 164eda9cec4SJosh Poimboeuf goto invalid_relocation; 1650fdc83b9SAmerigo Wang *(u64 *)loc = val; 1660fdc83b9SAmerigo Wang break; 1670fdc83b9SAmerigo Wang case R_X86_64_32: 168eda9cec4SJosh Poimboeuf if (*(u32 *)loc != 0) 169eda9cec4SJosh Poimboeuf goto invalid_relocation; 1700fdc83b9SAmerigo Wang *(u32 *)loc = val; 1710fdc83b9SAmerigo Wang if (val != *(u32 *)loc) 1720fdc83b9SAmerigo Wang goto overflow; 1730fdc83b9SAmerigo Wang break; 1740fdc83b9SAmerigo Wang case R_X86_64_32S: 175eda9cec4SJosh Poimboeuf if (*(s32 *)loc != 0) 176eda9cec4SJosh Poimboeuf goto invalid_relocation; 1770fdc83b9SAmerigo Wang *(s32 *)loc = val; 1780fdc83b9SAmerigo Wang if ((s64)val != *(s32 *)loc) 1790fdc83b9SAmerigo Wang goto overflow; 1800fdc83b9SAmerigo Wang break; 1810fdc83b9SAmerigo Wang case R_X86_64_PC32: 182b21ebf2fSH.J. Lu case R_X86_64_PLT32: 183eda9cec4SJosh Poimboeuf if (*(u32 *)loc != 0) 184eda9cec4SJosh Poimboeuf goto invalid_relocation; 1850fdc83b9SAmerigo Wang val -= (u64)loc; 1860fdc83b9SAmerigo Wang *(u32 *)loc = val; 1870fdc83b9SAmerigo Wang #if 0 1880fdc83b9SAmerigo Wang if ((s64)val != *(s32 *)loc) 1890fdc83b9SAmerigo Wang goto overflow; 1900fdc83b9SAmerigo Wang #endif 1910fdc83b9SAmerigo Wang break; 192b40a142bSArd Biesheuvel case R_X86_64_PC64: 193b40a142bSArd Biesheuvel if (*(u64 *)loc != 0) 194b40a142bSArd Biesheuvel goto invalid_relocation; 195b40a142bSArd Biesheuvel val -= (u64)loc; 196b40a142bSArd Biesheuvel *(u64 *)loc = val; 197b40a142bSArd Biesheuvel break; 1980fdc83b9SAmerigo Wang default: 199c767a54bSJoe Perches pr_err("%s: Unknown rela relocation: %llu\n", 2000fdc83b9SAmerigo Wang me->name, ELF64_R_TYPE(rel[i].r_info)); 2010fdc83b9SAmerigo Wang return -ENOEXEC; 2020fdc83b9SAmerigo Wang } 2030fdc83b9SAmerigo Wang } 2040fdc83b9SAmerigo Wang return 0; 2050fdc83b9SAmerigo Wang 206eda9cec4SJosh Poimboeuf invalid_relocation: 207eda9cec4SJosh Poimboeuf pr_err("x86/modules: Skipping invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n", 208eda9cec4SJosh Poimboeuf (int)ELF64_R_TYPE(rel[i].r_info), loc, val); 209eda9cec4SJosh Poimboeuf return -ENOEXEC; 210eda9cec4SJosh Poimboeuf 2110fdc83b9SAmerigo Wang overflow: 212c767a54bSJoe Perches pr_err("overflow in relocation type %d val %Lx\n", 2130fdc83b9SAmerigo Wang (int)ELF64_R_TYPE(rel[i].r_info), val); 214c767a54bSJoe Perches pr_err("`%s' likely not compiled with -mcmodel=kernel\n", 2150fdc83b9SAmerigo Wang me->name); 2160fdc83b9SAmerigo Wang return -ENOEXEC; 2170fdc83b9SAmerigo Wang } 2180fdc83b9SAmerigo Wang #endif 2190fdc83b9SAmerigo Wang 2202d5bf28fSAmerigo Wang int module_finalize(const Elf_Ehdr *hdr, 2212d5bf28fSAmerigo Wang const Elf_Shdr *sechdrs, 2222d5bf28fSAmerigo Wang struct module *me) 2232d5bf28fSAmerigo Wang { 2242d5bf28fSAmerigo Wang const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL, 225ee9f8fceSJosh Poimboeuf *para = NULL, *orc = NULL, *orc_ip = NULL; 2262d5bf28fSAmerigo Wang char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 2272d5bf28fSAmerigo Wang 2282d5bf28fSAmerigo Wang for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { 2292d5bf28fSAmerigo Wang if (!strcmp(".text", secstrings + s->sh_name)) 2302d5bf28fSAmerigo Wang text = s; 2312d5bf28fSAmerigo Wang if (!strcmp(".altinstructions", secstrings + s->sh_name)) 2322d5bf28fSAmerigo Wang alt = s; 2332d5bf28fSAmerigo Wang if (!strcmp(".smp_locks", secstrings + s->sh_name)) 2342d5bf28fSAmerigo Wang locks = s; 2352d5bf28fSAmerigo Wang if (!strcmp(".parainstructions", secstrings + s->sh_name)) 2362d5bf28fSAmerigo Wang para = s; 237ee9f8fceSJosh Poimboeuf if (!strcmp(".orc_unwind", secstrings + s->sh_name)) 238ee9f8fceSJosh Poimboeuf orc = s; 239ee9f8fceSJosh Poimboeuf if (!strcmp(".orc_unwind_ip", secstrings + s->sh_name)) 240ee9f8fceSJosh Poimboeuf orc_ip = s; 2412d5bf28fSAmerigo Wang } 2422d5bf28fSAmerigo Wang 2432d5bf28fSAmerigo Wang if (alt) { 2442d5bf28fSAmerigo Wang /* patch .altinstructions */ 2452d5bf28fSAmerigo Wang void *aseg = (void *)alt->sh_addr; 2462d5bf28fSAmerigo Wang apply_alternatives(aseg, aseg + alt->sh_size); 2472d5bf28fSAmerigo Wang } 2482d5bf28fSAmerigo Wang if (locks && text) { 2492d5bf28fSAmerigo Wang void *lseg = (void *)locks->sh_addr; 2502d5bf28fSAmerigo Wang void *tseg = (void *)text->sh_addr; 2512d5bf28fSAmerigo Wang alternatives_smp_module_add(me, me->name, 2522d5bf28fSAmerigo Wang lseg, lseg + locks->sh_size, 2532d5bf28fSAmerigo Wang tseg, tseg + text->sh_size); 2542d5bf28fSAmerigo Wang } 2552d5bf28fSAmerigo Wang 2562d5bf28fSAmerigo Wang if (para) { 2572d5bf28fSAmerigo Wang void *pseg = (void *)para->sh_addr; 2582d5bf28fSAmerigo Wang apply_paravirt(pseg, pseg + para->sh_size); 2592d5bf28fSAmerigo Wang } 2602d5bf28fSAmerigo Wang 261d9f5ab7bSJason Baron /* make jump label nops */ 262d9f5ab7bSJason Baron jump_label_apply_nops(me); 263d9f5ab7bSJason Baron 264ee9f8fceSJosh Poimboeuf if (orc && orc_ip) 265ee9f8fceSJosh Poimboeuf unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size, 266ee9f8fceSJosh Poimboeuf (void *)orc->sh_addr, orc->sh_size); 267ee9f8fceSJosh Poimboeuf 2685336377dSLinus Torvalds return 0; 2692d5bf28fSAmerigo Wang } 2702d5bf28fSAmerigo Wang 2712d5bf28fSAmerigo Wang void module_arch_cleanup(struct module *mod) 2722d5bf28fSAmerigo Wang { 2732d5bf28fSAmerigo Wang alternatives_smp_module_del(mod); 2742d5bf28fSAmerigo Wang } 275