xref: /openbmc/linux/arch/x86/kernel/module.c (revision b40a142b12b5c4312171140ff2bc92971b8a7a09)
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>
38ee9f8fceSJosh 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:
175eda9cec4SJosh Poimboeuf 			if (*(u64 *)loc != 0)
176eda9cec4SJosh Poimboeuf 				goto invalid_relocation;
1770fdc83b9SAmerigo Wang 			*(u64 *)loc = val;
1780fdc83b9SAmerigo Wang 			break;
1790fdc83b9SAmerigo Wang 		case R_X86_64_32:
180eda9cec4SJosh Poimboeuf 			if (*(u32 *)loc != 0)
181eda9cec4SJosh Poimboeuf 				goto invalid_relocation;
1820fdc83b9SAmerigo Wang 			*(u32 *)loc = val;
1830fdc83b9SAmerigo Wang 			if (val != *(u32 *)loc)
1840fdc83b9SAmerigo Wang 				goto overflow;
1850fdc83b9SAmerigo Wang 			break;
1860fdc83b9SAmerigo Wang 		case R_X86_64_32S:
187eda9cec4SJosh Poimboeuf 			if (*(s32 *)loc != 0)
188eda9cec4SJosh Poimboeuf 				goto invalid_relocation;
1890fdc83b9SAmerigo Wang 			*(s32 *)loc = val;
1900fdc83b9SAmerigo Wang 			if ((s64)val != *(s32 *)loc)
1910fdc83b9SAmerigo Wang 				goto overflow;
1920fdc83b9SAmerigo Wang 			break;
1930fdc83b9SAmerigo Wang 		case R_X86_64_PC32:
194b21ebf2fSH.J. Lu 		case R_X86_64_PLT32:
195eda9cec4SJosh Poimboeuf 			if (*(u32 *)loc != 0)
196eda9cec4SJosh Poimboeuf 				goto invalid_relocation;
1970fdc83b9SAmerigo Wang 			val -= (u64)loc;
1980fdc83b9SAmerigo Wang 			*(u32 *)loc = val;
1990fdc83b9SAmerigo Wang #if 0
2000fdc83b9SAmerigo Wang 			if ((s64)val != *(s32 *)loc)
2010fdc83b9SAmerigo Wang 				goto overflow;
2020fdc83b9SAmerigo Wang #endif
2030fdc83b9SAmerigo Wang 			break;
204*b40a142bSArd Biesheuvel 		case R_X86_64_PC64:
205*b40a142bSArd Biesheuvel 			if (*(u64 *)loc != 0)
206*b40a142bSArd Biesheuvel 				goto invalid_relocation;
207*b40a142bSArd Biesheuvel 			val -= (u64)loc;
208*b40a142bSArd Biesheuvel 			*(u64 *)loc = val;
209*b40a142bSArd Biesheuvel 			break;
2100fdc83b9SAmerigo Wang 		default:
211c767a54bSJoe Perches 			pr_err("%s: Unknown rela relocation: %llu\n",
2120fdc83b9SAmerigo Wang 			       me->name, ELF64_R_TYPE(rel[i].r_info));
2130fdc83b9SAmerigo Wang 			return -ENOEXEC;
2140fdc83b9SAmerigo Wang 		}
2150fdc83b9SAmerigo Wang 	}
2160fdc83b9SAmerigo Wang 	return 0;
2170fdc83b9SAmerigo Wang 
218eda9cec4SJosh Poimboeuf invalid_relocation:
219eda9cec4SJosh Poimboeuf 	pr_err("x86/modules: Skipping invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n",
220eda9cec4SJosh Poimboeuf 	       (int)ELF64_R_TYPE(rel[i].r_info), loc, val);
221eda9cec4SJosh Poimboeuf 	return -ENOEXEC;
222eda9cec4SJosh Poimboeuf 
2230fdc83b9SAmerigo Wang overflow:
224c767a54bSJoe Perches 	pr_err("overflow in relocation type %d val %Lx\n",
2250fdc83b9SAmerigo Wang 	       (int)ELF64_R_TYPE(rel[i].r_info), val);
226c767a54bSJoe Perches 	pr_err("`%s' likely not compiled with -mcmodel=kernel\n",
2270fdc83b9SAmerigo Wang 	       me->name);
2280fdc83b9SAmerigo Wang 	return -ENOEXEC;
2290fdc83b9SAmerigo Wang }
2300fdc83b9SAmerigo Wang #endif
2310fdc83b9SAmerigo Wang 
2322d5bf28fSAmerigo Wang int module_finalize(const Elf_Ehdr *hdr,
2332d5bf28fSAmerigo Wang 		    const Elf_Shdr *sechdrs,
2342d5bf28fSAmerigo Wang 		    struct module *me)
2352d5bf28fSAmerigo Wang {
2362d5bf28fSAmerigo Wang 	const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
237ee9f8fceSJosh Poimboeuf 		*para = NULL, *orc = NULL, *orc_ip = NULL;
2382d5bf28fSAmerigo Wang 	char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
2392d5bf28fSAmerigo Wang 
2402d5bf28fSAmerigo Wang 	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
2412d5bf28fSAmerigo Wang 		if (!strcmp(".text", secstrings + s->sh_name))
2422d5bf28fSAmerigo Wang 			text = s;
2432d5bf28fSAmerigo Wang 		if (!strcmp(".altinstructions", secstrings + s->sh_name))
2442d5bf28fSAmerigo Wang 			alt = s;
2452d5bf28fSAmerigo Wang 		if (!strcmp(".smp_locks", secstrings + s->sh_name))
2462d5bf28fSAmerigo Wang 			locks = s;
2472d5bf28fSAmerigo Wang 		if (!strcmp(".parainstructions", secstrings + s->sh_name))
2482d5bf28fSAmerigo Wang 			para = s;
249ee9f8fceSJosh Poimboeuf 		if (!strcmp(".orc_unwind", secstrings + s->sh_name))
250ee9f8fceSJosh Poimboeuf 			orc = s;
251ee9f8fceSJosh Poimboeuf 		if (!strcmp(".orc_unwind_ip", secstrings + s->sh_name))
252ee9f8fceSJosh Poimboeuf 			orc_ip = s;
2532d5bf28fSAmerigo Wang 	}
2542d5bf28fSAmerigo Wang 
2552d5bf28fSAmerigo Wang 	if (alt) {
2562d5bf28fSAmerigo Wang 		/* patch .altinstructions */
2572d5bf28fSAmerigo Wang 		void *aseg = (void *)alt->sh_addr;
2582d5bf28fSAmerigo Wang 		apply_alternatives(aseg, aseg + alt->sh_size);
2592d5bf28fSAmerigo Wang 	}
2602d5bf28fSAmerigo Wang 	if (locks && text) {
2612d5bf28fSAmerigo Wang 		void *lseg = (void *)locks->sh_addr;
2622d5bf28fSAmerigo Wang 		void *tseg = (void *)text->sh_addr;
2632d5bf28fSAmerigo Wang 		alternatives_smp_module_add(me, me->name,
2642d5bf28fSAmerigo Wang 					    lseg, lseg + locks->sh_size,
2652d5bf28fSAmerigo Wang 					    tseg, tseg + text->sh_size);
2662d5bf28fSAmerigo Wang 	}
2672d5bf28fSAmerigo Wang 
2682d5bf28fSAmerigo Wang 	if (para) {
2692d5bf28fSAmerigo Wang 		void *pseg = (void *)para->sh_addr;
2702d5bf28fSAmerigo Wang 		apply_paravirt(pseg, pseg + para->sh_size);
2712d5bf28fSAmerigo Wang 	}
2722d5bf28fSAmerigo Wang 
273d9f5ab7bSJason Baron 	/* make jump label nops */
274d9f5ab7bSJason Baron 	jump_label_apply_nops(me);
275d9f5ab7bSJason Baron 
276ee9f8fceSJosh Poimboeuf 	if (orc && orc_ip)
277ee9f8fceSJosh Poimboeuf 		unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size,
278ee9f8fceSJosh Poimboeuf 				   (void *)orc->sh_addr, orc->sh_size);
279ee9f8fceSJosh Poimboeuf 
2805336377dSLinus Torvalds 	return 0;
2812d5bf28fSAmerigo Wang }
2822d5bf28fSAmerigo Wang 
2832d5bf28fSAmerigo Wang void module_arch_cleanup(struct module *mod)
2842d5bf28fSAmerigo Wang {
2852d5bf28fSAmerigo Wang 	alternatives_smp_module_del(mod);
2862d5bf28fSAmerigo Wang }
287