xref: /openbmc/linux/arch/x86/kernel/module.c (revision 9dd721c6dbfc310f94306902611f86dda87a45fa)
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>
272d5bf28fSAmerigo Wang #include <linux/bug.h>
282d5bf28fSAmerigo Wang #include <linux/mm.h>
295a0e3ad6STejun Heo #include <linux/gfp.h>
30d430d3d7SJason Baron #include <linux/jump_label.h>
31e2b32e67SKees Cook #include <linux/random.h>
322d5bf28fSAmerigo Wang 
332d5bf28fSAmerigo Wang #include <asm/page.h>
342d5bf28fSAmerigo Wang #include <asm/pgtable.h>
352d5bf28fSAmerigo Wang 
362d5bf28fSAmerigo Wang #if 0
37c767a54bSJoe Perches #define DEBUGP(fmt, ...)				\
38c767a54bSJoe Perches 	printk(KERN_DEBUG fmt, ##__VA_ARGS__)
392d5bf28fSAmerigo Wang #else
40c767a54bSJoe Perches #define DEBUGP(fmt, ...)				\
41c767a54bSJoe Perches do {							\
42c767a54bSJoe Perches 	if (0)						\
43c767a54bSJoe Perches 		printk(KERN_DEBUG fmt, ##__VA_ARGS__);	\
44c767a54bSJoe Perches } while (0)
452d5bf28fSAmerigo Wang #endif
462d5bf28fSAmerigo Wang 
47e2b32e67SKees Cook #ifdef CONFIG_RANDOMIZE_BASE
48e2b32e67SKees Cook static unsigned long module_load_offset;
49e2b32e67SKees Cook static int randomize_modules = 1;
50e2b32e67SKees Cook 
51*9dd721c6SKees Cook /* Mutex protects the module_load_offset. */
52*9dd721c6SKees Cook static DEFINE_MUTEX(module_kaslr_mutex);
53*9dd721c6SKees Cook 
54e2b32e67SKees Cook static int __init parse_nokaslr(char *p)
55e2b32e67SKees Cook {
56e2b32e67SKees Cook 	randomize_modules = 0;
57e2b32e67SKees Cook 	return 0;
58e2b32e67SKees Cook }
59e2b32e67SKees Cook early_param("nokaslr", parse_nokaslr);
60e2b32e67SKees Cook 
61e2b32e67SKees Cook static unsigned long int get_module_load_offset(void)
62e2b32e67SKees Cook {
63e2b32e67SKees Cook 	if (randomize_modules) {
64*9dd721c6SKees Cook 		mutex_lock(&module_kaslr_mutex);
65e2b32e67SKees Cook 		/*
66e2b32e67SKees Cook 		 * Calculate the module_load_offset the first time this
67e2b32e67SKees Cook 		 * code is called. Once calculated it stays the same until
68e2b32e67SKees Cook 		 * reboot.
69e2b32e67SKees Cook 		 */
70e2b32e67SKees Cook 		if (module_load_offset == 0)
71e2b32e67SKees Cook 			module_load_offset =
72e2b32e67SKees Cook 				(get_random_int() % 1024 + 1) * PAGE_SIZE;
73*9dd721c6SKees Cook 		mutex_unlock(&module_kaslr_mutex);
74e2b32e67SKees Cook 	}
75e2b32e67SKees Cook 	return module_load_offset;
76e2b32e67SKees Cook }
77e2b32e67SKees Cook #else
78e2b32e67SKees Cook static unsigned long int get_module_load_offset(void)
79e2b32e67SKees Cook {
80e2b32e67SKees Cook 	return 0;
81e2b32e67SKees Cook }
82e2b32e67SKees Cook #endif
83e2b32e67SKees Cook 
840fdc83b9SAmerigo Wang void *module_alloc(unsigned long size)
850fdc83b9SAmerigo Wang {
86d0a21265SDavid Rientjes 	if (PAGE_ALIGN(size) > MODULES_LEN)
870fdc83b9SAmerigo Wang 		return NULL;
88e2b32e67SKees Cook 	return __vmalloc_node_range(size, 1,
89e2b32e67SKees Cook 				    MODULES_VADDR + get_module_load_offset(),
90e2b32e67SKees Cook 				    MODULES_END, GFP_KERNEL | __GFP_HIGHMEM,
91e2b32e67SKees Cook 				    PAGE_KERNEL_EXEC, NUMA_NO_NODE,
92e2b32e67SKees Cook 				    __builtin_return_address(0));
930fdc83b9SAmerigo Wang }
940fdc83b9SAmerigo Wang 
950fdc83b9SAmerigo Wang #ifdef CONFIG_X86_32
960fdc83b9SAmerigo Wang int apply_relocate(Elf32_Shdr *sechdrs,
970fdc83b9SAmerigo Wang 		   const char *strtab,
980fdc83b9SAmerigo Wang 		   unsigned int symindex,
990fdc83b9SAmerigo Wang 		   unsigned int relsec,
1000fdc83b9SAmerigo Wang 		   struct module *me)
1010fdc83b9SAmerigo Wang {
1020fdc83b9SAmerigo Wang 	unsigned int i;
1030fdc83b9SAmerigo Wang 	Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
1040fdc83b9SAmerigo Wang 	Elf32_Sym *sym;
1050fdc83b9SAmerigo Wang 	uint32_t *location;
1060fdc83b9SAmerigo Wang 
107c767a54bSJoe Perches 	DEBUGP("Applying relocate section %u to %u\n",
108c767a54bSJoe Perches 	       relsec, sechdrs[relsec].sh_info);
1090fdc83b9SAmerigo Wang 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
1100fdc83b9SAmerigo Wang 		/* This is where to make the change */
1110fdc83b9SAmerigo Wang 		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
1120fdc83b9SAmerigo Wang 			+ rel[i].r_offset;
1130fdc83b9SAmerigo Wang 		/* This is the symbol it is referring to.  Note that all
1140fdc83b9SAmerigo Wang 		   undefined symbols have been resolved.  */
1150fdc83b9SAmerigo Wang 		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
1160fdc83b9SAmerigo Wang 			+ ELF32_R_SYM(rel[i].r_info);
1170fdc83b9SAmerigo Wang 
1180fdc83b9SAmerigo Wang 		switch (ELF32_R_TYPE(rel[i].r_info)) {
1190fdc83b9SAmerigo Wang 		case R_386_32:
1200fdc83b9SAmerigo Wang 			/* We add the value into the location given */
1210fdc83b9SAmerigo Wang 			*location += sym->st_value;
1220fdc83b9SAmerigo Wang 			break;
1230fdc83b9SAmerigo Wang 		case R_386_PC32:
1242e76c283SGeert Uytterhoeven 			/* Add the value, subtract its position */
1250fdc83b9SAmerigo Wang 			*location += sym->st_value - (uint32_t)location;
1260fdc83b9SAmerigo Wang 			break;
1270fdc83b9SAmerigo Wang 		default:
128c767a54bSJoe Perches 			pr_err("%s: Unknown relocation: %u\n",
1290fdc83b9SAmerigo Wang 			       me->name, ELF32_R_TYPE(rel[i].r_info));
1300fdc83b9SAmerigo Wang 			return -ENOEXEC;
1310fdc83b9SAmerigo Wang 		}
1320fdc83b9SAmerigo Wang 	}
1330fdc83b9SAmerigo Wang 	return 0;
1340fdc83b9SAmerigo Wang }
1350fdc83b9SAmerigo Wang #else /*X86_64*/
1360fdc83b9SAmerigo Wang int apply_relocate_add(Elf64_Shdr *sechdrs,
1370fdc83b9SAmerigo Wang 		   const char *strtab,
1380fdc83b9SAmerigo Wang 		   unsigned int symindex,
1390fdc83b9SAmerigo Wang 		   unsigned int relsec,
1400fdc83b9SAmerigo Wang 		   struct module *me)
1410fdc83b9SAmerigo Wang {
1420fdc83b9SAmerigo Wang 	unsigned int i;
1430fdc83b9SAmerigo Wang 	Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
1440fdc83b9SAmerigo Wang 	Elf64_Sym *sym;
1450fdc83b9SAmerigo Wang 	void *loc;
1460fdc83b9SAmerigo Wang 	u64 val;
1470fdc83b9SAmerigo Wang 
148c767a54bSJoe Perches 	DEBUGP("Applying relocate section %u to %u\n",
149c767a54bSJoe Perches 	       relsec, sechdrs[relsec].sh_info);
1500fdc83b9SAmerigo Wang 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
1510fdc83b9SAmerigo Wang 		/* This is where to make the change */
1520fdc83b9SAmerigo Wang 		loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
1530fdc83b9SAmerigo Wang 			+ rel[i].r_offset;
1540fdc83b9SAmerigo Wang 
1550fdc83b9SAmerigo Wang 		/* This is the symbol it is referring to.  Note that all
1560fdc83b9SAmerigo Wang 		   undefined symbols have been resolved.  */
1570fdc83b9SAmerigo Wang 		sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
1580fdc83b9SAmerigo Wang 			+ ELF64_R_SYM(rel[i].r_info);
1590fdc83b9SAmerigo Wang 
1600fdc83b9SAmerigo Wang 		DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
1610fdc83b9SAmerigo Wang 		       (int)ELF64_R_TYPE(rel[i].r_info),
1620fdc83b9SAmerigo Wang 		       sym->st_value, rel[i].r_addend, (u64)loc);
1630fdc83b9SAmerigo Wang 
1640fdc83b9SAmerigo Wang 		val = sym->st_value + rel[i].r_addend;
1650fdc83b9SAmerigo Wang 
1660fdc83b9SAmerigo Wang 		switch (ELF64_R_TYPE(rel[i].r_info)) {
1670fdc83b9SAmerigo Wang 		case R_X86_64_NONE:
1680fdc83b9SAmerigo Wang 			break;
1690fdc83b9SAmerigo Wang 		case R_X86_64_64:
1700fdc83b9SAmerigo Wang 			*(u64 *)loc = val;
1710fdc83b9SAmerigo Wang 			break;
1720fdc83b9SAmerigo Wang 		case R_X86_64_32:
1730fdc83b9SAmerigo Wang 			*(u32 *)loc = val;
1740fdc83b9SAmerigo Wang 			if (val != *(u32 *)loc)
1750fdc83b9SAmerigo Wang 				goto overflow;
1760fdc83b9SAmerigo Wang 			break;
1770fdc83b9SAmerigo Wang 		case R_X86_64_32S:
1780fdc83b9SAmerigo Wang 			*(s32 *)loc = val;
1790fdc83b9SAmerigo Wang 			if ((s64)val != *(s32 *)loc)
1800fdc83b9SAmerigo Wang 				goto overflow;
1810fdc83b9SAmerigo Wang 			break;
1820fdc83b9SAmerigo Wang 		case R_X86_64_PC32:
1830fdc83b9SAmerigo Wang 			val -= (u64)loc;
1840fdc83b9SAmerigo Wang 			*(u32 *)loc = val;
1850fdc83b9SAmerigo Wang #if 0
1860fdc83b9SAmerigo Wang 			if ((s64)val != *(s32 *)loc)
1870fdc83b9SAmerigo Wang 				goto overflow;
1880fdc83b9SAmerigo Wang #endif
1890fdc83b9SAmerigo Wang 			break;
1900fdc83b9SAmerigo Wang 		default:
191c767a54bSJoe Perches 			pr_err("%s: Unknown rela relocation: %llu\n",
1920fdc83b9SAmerigo Wang 			       me->name, ELF64_R_TYPE(rel[i].r_info));
1930fdc83b9SAmerigo Wang 			return -ENOEXEC;
1940fdc83b9SAmerigo Wang 		}
1950fdc83b9SAmerigo Wang 	}
1960fdc83b9SAmerigo Wang 	return 0;
1970fdc83b9SAmerigo Wang 
1980fdc83b9SAmerigo Wang overflow:
199c767a54bSJoe Perches 	pr_err("overflow in relocation type %d val %Lx\n",
2000fdc83b9SAmerigo Wang 	       (int)ELF64_R_TYPE(rel[i].r_info), val);
201c767a54bSJoe Perches 	pr_err("`%s' likely not compiled with -mcmodel=kernel\n",
2020fdc83b9SAmerigo Wang 	       me->name);
2030fdc83b9SAmerigo Wang 	return -ENOEXEC;
2040fdc83b9SAmerigo Wang }
2050fdc83b9SAmerigo Wang #endif
2060fdc83b9SAmerigo Wang 
2072d5bf28fSAmerigo Wang int module_finalize(const Elf_Ehdr *hdr,
2082d5bf28fSAmerigo Wang 		    const Elf_Shdr *sechdrs,
2092d5bf28fSAmerigo Wang 		    struct module *me)
2102d5bf28fSAmerigo Wang {
2112d5bf28fSAmerigo Wang 	const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
2122d5bf28fSAmerigo Wang 		*para = NULL;
2132d5bf28fSAmerigo Wang 	char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
2142d5bf28fSAmerigo Wang 
2152d5bf28fSAmerigo Wang 	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
2162d5bf28fSAmerigo Wang 		if (!strcmp(".text", secstrings + s->sh_name))
2172d5bf28fSAmerigo Wang 			text = s;
2182d5bf28fSAmerigo Wang 		if (!strcmp(".altinstructions", secstrings + s->sh_name))
2192d5bf28fSAmerigo Wang 			alt = s;
2202d5bf28fSAmerigo Wang 		if (!strcmp(".smp_locks", secstrings + s->sh_name))
2212d5bf28fSAmerigo Wang 			locks = s;
2222d5bf28fSAmerigo Wang 		if (!strcmp(".parainstructions", secstrings + s->sh_name))
2232d5bf28fSAmerigo Wang 			para = s;
2242d5bf28fSAmerigo Wang 	}
2252d5bf28fSAmerigo Wang 
2262d5bf28fSAmerigo Wang 	if (alt) {
2272d5bf28fSAmerigo Wang 		/* patch .altinstructions */
2282d5bf28fSAmerigo Wang 		void *aseg = (void *)alt->sh_addr;
2292d5bf28fSAmerigo Wang 		apply_alternatives(aseg, aseg + alt->sh_size);
2302d5bf28fSAmerigo Wang 	}
2312d5bf28fSAmerigo Wang 	if (locks && text) {
2322d5bf28fSAmerigo Wang 		void *lseg = (void *)locks->sh_addr;
2332d5bf28fSAmerigo Wang 		void *tseg = (void *)text->sh_addr;
2342d5bf28fSAmerigo Wang 		alternatives_smp_module_add(me, me->name,
2352d5bf28fSAmerigo Wang 					    lseg, lseg + locks->sh_size,
2362d5bf28fSAmerigo Wang 					    tseg, tseg + text->sh_size);
2372d5bf28fSAmerigo Wang 	}
2382d5bf28fSAmerigo Wang 
2392d5bf28fSAmerigo Wang 	if (para) {
2402d5bf28fSAmerigo Wang 		void *pseg = (void *)para->sh_addr;
2412d5bf28fSAmerigo Wang 		apply_paravirt(pseg, pseg + para->sh_size);
2422d5bf28fSAmerigo Wang 	}
2432d5bf28fSAmerigo Wang 
244d9f5ab7bSJason Baron 	/* make jump label nops */
245d9f5ab7bSJason Baron 	jump_label_apply_nops(me);
246d9f5ab7bSJason Baron 
2475336377dSLinus Torvalds 	return 0;
2482d5bf28fSAmerigo Wang }
2492d5bf28fSAmerigo Wang 
2502d5bf28fSAmerigo Wang void module_arch_cleanup(struct module *mod)
2512d5bf28fSAmerigo Wang {
2522d5bf28fSAmerigo Wang 	alternatives_smp_module_del(mod);
2532d5bf28fSAmerigo Wang }
254