12d5bf28fSAmerigo Wang /* Kernel module help for x86. 22d5bf28fSAmerigo Wang Copyright (C) 2001 Rusty Russell. 32d5bf28fSAmerigo Wang 42d5bf28fSAmerigo Wang This program is free software; you can redistribute it and/or modify 52d5bf28fSAmerigo Wang it under the terms of the GNU General Public License as published by 62d5bf28fSAmerigo Wang the Free Software Foundation; either version 2 of the License, or 72d5bf28fSAmerigo Wang (at your option) any later version. 82d5bf28fSAmerigo Wang 92d5bf28fSAmerigo Wang This program is distributed in the hope that it will be useful, 102d5bf28fSAmerigo Wang but WITHOUT ANY WARRANTY; without even the implied warranty of 112d5bf28fSAmerigo Wang MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 122d5bf28fSAmerigo Wang GNU General Public License for more details. 132d5bf28fSAmerigo Wang 142d5bf28fSAmerigo Wang You should have received a copy of the GNU General Public License 152d5bf28fSAmerigo Wang along with this program; if not, write to the Free Software 162d5bf28fSAmerigo Wang Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 172d5bf28fSAmerigo Wang */ 18c767a54bSJoe Perches 19c767a54bSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 20c767a54bSJoe Perches 212d5bf28fSAmerigo Wang #include <linux/moduleloader.h> 222d5bf28fSAmerigo Wang #include <linux/elf.h> 232d5bf28fSAmerigo Wang #include <linux/vmalloc.h> 242d5bf28fSAmerigo Wang #include <linux/fs.h> 252d5bf28fSAmerigo Wang #include <linux/string.h> 262d5bf28fSAmerigo Wang #include <linux/kernel.h> 27bebf56a1SAndrey Ryabinin #include <linux/kasan.h> 282d5bf28fSAmerigo Wang #include <linux/bug.h> 292d5bf28fSAmerigo Wang #include <linux/mm.h> 305a0e3ad6STejun Heo #include <linux/gfp.h> 31d430d3d7SJason Baron #include <linux/jump_label.h> 32e2b32e67SKees Cook #include <linux/random.h> 332d5bf28fSAmerigo Wang 3435de5b06SAndy Lutomirski #include <asm/text-patching.h> 352d5bf28fSAmerigo Wang #include <asm/page.h> 362d5bf28fSAmerigo Wang #include <asm/pgtable.h> 3778cac48cSBorislav Petkov #include <asm/setup.h> 38*ee9f8fceSJosh Poimboeuf #include <asm/unwind.h> 392d5bf28fSAmerigo Wang 402d5bf28fSAmerigo Wang #if 0 41c767a54bSJoe Perches #define DEBUGP(fmt, ...) \ 42c767a54bSJoe Perches printk(KERN_DEBUG fmt, ##__VA_ARGS__) 432d5bf28fSAmerigo Wang #else 44c767a54bSJoe Perches #define DEBUGP(fmt, ...) \ 45c767a54bSJoe Perches do { \ 46c767a54bSJoe Perches if (0) \ 47c767a54bSJoe Perches printk(KERN_DEBUG fmt, ##__VA_ARGS__); \ 48c767a54bSJoe Perches } while (0) 492d5bf28fSAmerigo Wang #endif 502d5bf28fSAmerigo Wang 51e2b32e67SKees Cook #ifdef CONFIG_RANDOMIZE_BASE 52e2b32e67SKees Cook static unsigned long module_load_offset; 53e2b32e67SKees Cook 549dd721c6SKees Cook /* Mutex protects the module_load_offset. */ 559dd721c6SKees Cook static DEFINE_MUTEX(module_kaslr_mutex); 569dd721c6SKees Cook 57e2b32e67SKees Cook static unsigned long int get_module_load_offset(void) 58e2b32e67SKees Cook { 5978cac48cSBorislav Petkov if (kaslr_enabled()) { 609dd721c6SKees Cook mutex_lock(&module_kaslr_mutex); 61e2b32e67SKees Cook /* 62e2b32e67SKees Cook * Calculate the module_load_offset the first time this 63e2b32e67SKees Cook * code is called. Once calculated it stays the same until 64e2b32e67SKees Cook * reboot. 65e2b32e67SKees Cook */ 66e2b32e67SKees Cook if (module_load_offset == 0) 67e2b32e67SKees Cook module_load_offset = 68e2b32e67SKees Cook (get_random_int() % 1024 + 1) * PAGE_SIZE; 699dd721c6SKees Cook mutex_unlock(&module_kaslr_mutex); 70e2b32e67SKees Cook } 71e2b32e67SKees Cook return module_load_offset; 72e2b32e67SKees Cook } 73e2b32e67SKees Cook #else 74e2b32e67SKees Cook static unsigned long int get_module_load_offset(void) 75e2b32e67SKees Cook { 76e2b32e67SKees Cook return 0; 77e2b32e67SKees Cook } 78e2b32e67SKees Cook #endif 79e2b32e67SKees Cook 800fdc83b9SAmerigo Wang void *module_alloc(unsigned long size) 810fdc83b9SAmerigo Wang { 82bebf56a1SAndrey Ryabinin void *p; 83bebf56a1SAndrey Ryabinin 84d0a21265SDavid Rientjes if (PAGE_ALIGN(size) > MODULES_LEN) 850fdc83b9SAmerigo Wang return NULL; 86bebf56a1SAndrey Ryabinin 87bebf56a1SAndrey Ryabinin p = __vmalloc_node_range(size, MODULE_ALIGN, 88e2b32e67SKees Cook MODULES_VADDR + get_module_load_offset(), 8919809c2dSMichal Hocko MODULES_END, GFP_KERNEL, 90cb9e3c29SAndrey Ryabinin PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, 91e2b32e67SKees Cook __builtin_return_address(0)); 92bebf56a1SAndrey Ryabinin if (p && (kasan_module_alloc(p, size) < 0)) { 93bebf56a1SAndrey Ryabinin vfree(p); 94bebf56a1SAndrey Ryabinin return NULL; 95bebf56a1SAndrey Ryabinin } 96bebf56a1SAndrey Ryabinin 97bebf56a1SAndrey Ryabinin return p; 980fdc83b9SAmerigo Wang } 990fdc83b9SAmerigo Wang 1000fdc83b9SAmerigo Wang #ifdef CONFIG_X86_32 1010fdc83b9SAmerigo Wang int apply_relocate(Elf32_Shdr *sechdrs, 1020fdc83b9SAmerigo Wang const char *strtab, 1030fdc83b9SAmerigo Wang unsigned int symindex, 1040fdc83b9SAmerigo Wang unsigned int relsec, 1050fdc83b9SAmerigo Wang struct module *me) 1060fdc83b9SAmerigo Wang { 1070fdc83b9SAmerigo Wang unsigned int i; 1080fdc83b9SAmerigo Wang Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; 1090fdc83b9SAmerigo Wang Elf32_Sym *sym; 1100fdc83b9SAmerigo Wang uint32_t *location; 1110fdc83b9SAmerigo Wang 112c767a54bSJoe Perches DEBUGP("Applying relocate section %u to %u\n", 113c767a54bSJoe Perches relsec, sechdrs[relsec].sh_info); 1140fdc83b9SAmerigo Wang for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 1150fdc83b9SAmerigo Wang /* This is where to make the change */ 1160fdc83b9SAmerigo Wang location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 1170fdc83b9SAmerigo Wang + rel[i].r_offset; 1180fdc83b9SAmerigo Wang /* This is the symbol it is referring to. Note that all 1190fdc83b9SAmerigo Wang undefined symbols have been resolved. */ 1200fdc83b9SAmerigo Wang sym = (Elf32_Sym *)sechdrs[symindex].sh_addr 1210fdc83b9SAmerigo Wang + ELF32_R_SYM(rel[i].r_info); 1220fdc83b9SAmerigo Wang 1230fdc83b9SAmerigo Wang switch (ELF32_R_TYPE(rel[i].r_info)) { 1240fdc83b9SAmerigo Wang case R_386_32: 1250fdc83b9SAmerigo Wang /* We add the value into the location given */ 1260fdc83b9SAmerigo Wang *location += sym->st_value; 1270fdc83b9SAmerigo Wang break; 1280fdc83b9SAmerigo Wang case R_386_PC32: 1292e76c283SGeert Uytterhoeven /* Add the value, subtract its position */ 1300fdc83b9SAmerigo Wang *location += sym->st_value - (uint32_t)location; 1310fdc83b9SAmerigo Wang break; 1320fdc83b9SAmerigo Wang default: 133c767a54bSJoe Perches pr_err("%s: Unknown relocation: %u\n", 1340fdc83b9SAmerigo Wang me->name, ELF32_R_TYPE(rel[i].r_info)); 1350fdc83b9SAmerigo Wang return -ENOEXEC; 1360fdc83b9SAmerigo Wang } 1370fdc83b9SAmerigo Wang } 1380fdc83b9SAmerigo Wang return 0; 1390fdc83b9SAmerigo Wang } 1400fdc83b9SAmerigo Wang #else /*X86_64*/ 1410fdc83b9SAmerigo Wang int apply_relocate_add(Elf64_Shdr *sechdrs, 1420fdc83b9SAmerigo Wang const char *strtab, 1430fdc83b9SAmerigo Wang unsigned int symindex, 1440fdc83b9SAmerigo Wang unsigned int relsec, 1450fdc83b9SAmerigo Wang struct module *me) 1460fdc83b9SAmerigo Wang { 1470fdc83b9SAmerigo Wang unsigned int i; 1480fdc83b9SAmerigo Wang Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; 1490fdc83b9SAmerigo Wang Elf64_Sym *sym; 1500fdc83b9SAmerigo Wang void *loc; 1510fdc83b9SAmerigo Wang u64 val; 1520fdc83b9SAmerigo Wang 153c767a54bSJoe Perches DEBUGP("Applying relocate section %u to %u\n", 154c767a54bSJoe Perches relsec, sechdrs[relsec].sh_info); 1550fdc83b9SAmerigo Wang for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { 1560fdc83b9SAmerigo Wang /* This is where to make the change */ 1570fdc83b9SAmerigo Wang loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr 1580fdc83b9SAmerigo Wang + rel[i].r_offset; 1590fdc83b9SAmerigo Wang 1600fdc83b9SAmerigo Wang /* This is the symbol it is referring to. Note that all 1610fdc83b9SAmerigo Wang undefined symbols have been resolved. */ 1620fdc83b9SAmerigo Wang sym = (Elf64_Sym *)sechdrs[symindex].sh_addr 1630fdc83b9SAmerigo Wang + ELF64_R_SYM(rel[i].r_info); 1640fdc83b9SAmerigo Wang 1650fdc83b9SAmerigo Wang DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n", 1660fdc83b9SAmerigo Wang (int)ELF64_R_TYPE(rel[i].r_info), 1670fdc83b9SAmerigo Wang sym->st_value, rel[i].r_addend, (u64)loc); 1680fdc83b9SAmerigo Wang 1690fdc83b9SAmerigo Wang val = sym->st_value + rel[i].r_addend; 1700fdc83b9SAmerigo Wang 1710fdc83b9SAmerigo Wang switch (ELF64_R_TYPE(rel[i].r_info)) { 1720fdc83b9SAmerigo Wang case R_X86_64_NONE: 1730fdc83b9SAmerigo Wang break; 1740fdc83b9SAmerigo Wang case R_X86_64_64: 1750fdc83b9SAmerigo Wang *(u64 *)loc = val; 1760fdc83b9SAmerigo Wang break; 1770fdc83b9SAmerigo Wang case R_X86_64_32: 1780fdc83b9SAmerigo Wang *(u32 *)loc = val; 1790fdc83b9SAmerigo Wang if (val != *(u32 *)loc) 1800fdc83b9SAmerigo Wang goto overflow; 1810fdc83b9SAmerigo Wang break; 1820fdc83b9SAmerigo Wang case R_X86_64_32S: 1830fdc83b9SAmerigo Wang *(s32 *)loc = val; 1840fdc83b9SAmerigo Wang if ((s64)val != *(s32 *)loc) 1850fdc83b9SAmerigo Wang goto overflow; 1860fdc83b9SAmerigo Wang break; 1870fdc83b9SAmerigo Wang case R_X86_64_PC32: 1880fdc83b9SAmerigo Wang val -= (u64)loc; 1890fdc83b9SAmerigo Wang *(u32 *)loc = val; 1900fdc83b9SAmerigo Wang #if 0 1910fdc83b9SAmerigo Wang if ((s64)val != *(s32 *)loc) 1920fdc83b9SAmerigo Wang goto overflow; 1930fdc83b9SAmerigo Wang #endif 1940fdc83b9SAmerigo Wang break; 1950fdc83b9SAmerigo Wang default: 196c767a54bSJoe Perches pr_err("%s: Unknown rela relocation: %llu\n", 1970fdc83b9SAmerigo Wang me->name, ELF64_R_TYPE(rel[i].r_info)); 1980fdc83b9SAmerigo Wang return -ENOEXEC; 1990fdc83b9SAmerigo Wang } 2000fdc83b9SAmerigo Wang } 2010fdc83b9SAmerigo Wang return 0; 2020fdc83b9SAmerigo Wang 2030fdc83b9SAmerigo Wang overflow: 204c767a54bSJoe Perches pr_err("overflow in relocation type %d val %Lx\n", 2050fdc83b9SAmerigo Wang (int)ELF64_R_TYPE(rel[i].r_info), val); 206c767a54bSJoe Perches pr_err("`%s' likely not compiled with -mcmodel=kernel\n", 2070fdc83b9SAmerigo Wang me->name); 2080fdc83b9SAmerigo Wang return -ENOEXEC; 2090fdc83b9SAmerigo Wang } 2100fdc83b9SAmerigo Wang #endif 2110fdc83b9SAmerigo Wang 2122d5bf28fSAmerigo Wang int module_finalize(const Elf_Ehdr *hdr, 2132d5bf28fSAmerigo Wang const Elf_Shdr *sechdrs, 2142d5bf28fSAmerigo Wang struct module *me) 2152d5bf28fSAmerigo Wang { 2162d5bf28fSAmerigo Wang const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL, 217*ee9f8fceSJosh Poimboeuf *para = NULL, *orc = NULL, *orc_ip = NULL; 2182d5bf28fSAmerigo Wang char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 2192d5bf28fSAmerigo Wang 2202d5bf28fSAmerigo Wang for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { 2212d5bf28fSAmerigo Wang if (!strcmp(".text", secstrings + s->sh_name)) 2222d5bf28fSAmerigo Wang text = s; 2232d5bf28fSAmerigo Wang if (!strcmp(".altinstructions", secstrings + s->sh_name)) 2242d5bf28fSAmerigo Wang alt = s; 2252d5bf28fSAmerigo Wang if (!strcmp(".smp_locks", secstrings + s->sh_name)) 2262d5bf28fSAmerigo Wang locks = s; 2272d5bf28fSAmerigo Wang if (!strcmp(".parainstructions", secstrings + s->sh_name)) 2282d5bf28fSAmerigo Wang para = s; 229*ee9f8fceSJosh Poimboeuf if (!strcmp(".orc_unwind", secstrings + s->sh_name)) 230*ee9f8fceSJosh Poimboeuf orc = s; 231*ee9f8fceSJosh Poimboeuf if (!strcmp(".orc_unwind_ip", secstrings + s->sh_name)) 232*ee9f8fceSJosh Poimboeuf orc_ip = s; 2332d5bf28fSAmerigo Wang } 2342d5bf28fSAmerigo Wang 2352d5bf28fSAmerigo Wang if (alt) { 2362d5bf28fSAmerigo Wang /* patch .altinstructions */ 2372d5bf28fSAmerigo Wang void *aseg = (void *)alt->sh_addr; 2382d5bf28fSAmerigo Wang apply_alternatives(aseg, aseg + alt->sh_size); 2392d5bf28fSAmerigo Wang } 2402d5bf28fSAmerigo Wang if (locks && text) { 2412d5bf28fSAmerigo Wang void *lseg = (void *)locks->sh_addr; 2422d5bf28fSAmerigo Wang void *tseg = (void *)text->sh_addr; 2432d5bf28fSAmerigo Wang alternatives_smp_module_add(me, me->name, 2442d5bf28fSAmerigo Wang lseg, lseg + locks->sh_size, 2452d5bf28fSAmerigo Wang tseg, tseg + text->sh_size); 2462d5bf28fSAmerigo Wang } 2472d5bf28fSAmerigo Wang 2482d5bf28fSAmerigo Wang if (para) { 2492d5bf28fSAmerigo Wang void *pseg = (void *)para->sh_addr; 2502d5bf28fSAmerigo Wang apply_paravirt(pseg, pseg + para->sh_size); 2512d5bf28fSAmerigo Wang } 2522d5bf28fSAmerigo Wang 253d9f5ab7bSJason Baron /* make jump label nops */ 254d9f5ab7bSJason Baron jump_label_apply_nops(me); 255d9f5ab7bSJason Baron 256*ee9f8fceSJosh Poimboeuf if (orc && orc_ip) 257*ee9f8fceSJosh Poimboeuf unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size, 258*ee9f8fceSJosh Poimboeuf (void *)orc->sh_addr, orc->sh_size); 259*ee9f8fceSJosh Poimboeuf 2605336377dSLinus Torvalds return 0; 2612d5bf28fSAmerigo Wang } 2622d5bf28fSAmerigo Wang 2632d5bf28fSAmerigo Wang void module_arch_cleanup(struct module *mod) 2642d5bf28fSAmerigo Wang { 2652d5bf28fSAmerigo Wang alternatives_smp_module_del(mod); 2662d5bf28fSAmerigo Wang } 267