xref: /openbmc/linux/arch/x86/kernel/module.c (revision 88fc078a7a8f67e47020d73d8d14ed11f03754ab)
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>
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*/
129*88fc078aSPeter Zijlstra static int __apply_relocate_add(Elf64_Shdr *sechdrs,
1300fdc83b9SAmerigo Wang 		   const char *strtab,
1310fdc83b9SAmerigo Wang 		   unsigned int symindex,
1320fdc83b9SAmerigo Wang 		   unsigned int relsec,
133*88fc078aSPeter Zijlstra 		   struct module *me,
134*88fc078aSPeter Zijlstra 		   void *(*write)(void *dest, const void *src, size_t len))
1350fdc83b9SAmerigo Wang {
1360fdc83b9SAmerigo Wang 	unsigned int i;
1370fdc83b9SAmerigo Wang 	Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
1380fdc83b9SAmerigo Wang 	Elf64_Sym *sym;
1390fdc83b9SAmerigo Wang 	void *loc;
1400fdc83b9SAmerigo Wang 	u64 val;
1410fdc83b9SAmerigo Wang 
142c767a54bSJoe Perches 	DEBUGP("Applying relocate section %u to %u\n",
143c767a54bSJoe Perches 	       relsec, sechdrs[relsec].sh_info);
1440fdc83b9SAmerigo Wang 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
1450fdc83b9SAmerigo Wang 		/* This is where to make the change */
1460fdc83b9SAmerigo Wang 		loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
1470fdc83b9SAmerigo Wang 			+ rel[i].r_offset;
1480fdc83b9SAmerigo Wang 
1490fdc83b9SAmerigo Wang 		/* This is the symbol it is referring to.  Note that all
1500fdc83b9SAmerigo Wang 		   undefined symbols have been resolved.  */
1510fdc83b9SAmerigo Wang 		sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
1520fdc83b9SAmerigo Wang 			+ ELF64_R_SYM(rel[i].r_info);
1530fdc83b9SAmerigo Wang 
1540fdc83b9SAmerigo Wang 		DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
1550fdc83b9SAmerigo Wang 		       (int)ELF64_R_TYPE(rel[i].r_info),
1560fdc83b9SAmerigo Wang 		       sym->st_value, rel[i].r_addend, (u64)loc);
1570fdc83b9SAmerigo Wang 
1580fdc83b9SAmerigo Wang 		val = sym->st_value + rel[i].r_addend;
1590fdc83b9SAmerigo Wang 
1600fdc83b9SAmerigo Wang 		switch (ELF64_R_TYPE(rel[i].r_info)) {
1610fdc83b9SAmerigo Wang 		case R_X86_64_NONE:
1620fdc83b9SAmerigo Wang 			break;
1630fdc83b9SAmerigo Wang 		case R_X86_64_64:
164eda9cec4SJosh Poimboeuf 			if (*(u64 *)loc != 0)
165eda9cec4SJosh Poimboeuf 				goto invalid_relocation;
166*88fc078aSPeter Zijlstra 			write(loc, &val, 8);
1670fdc83b9SAmerigo Wang 			break;
1680fdc83b9SAmerigo Wang 		case R_X86_64_32:
169eda9cec4SJosh Poimboeuf 			if (*(u32 *)loc != 0)
170eda9cec4SJosh Poimboeuf 				goto invalid_relocation;
171*88fc078aSPeter Zijlstra 			write(loc, &val, 4);
1720fdc83b9SAmerigo Wang 			if (val != *(u32 *)loc)
1730fdc83b9SAmerigo Wang 				goto overflow;
1740fdc83b9SAmerigo Wang 			break;
1750fdc83b9SAmerigo Wang 		case R_X86_64_32S:
176eda9cec4SJosh Poimboeuf 			if (*(s32 *)loc != 0)
177eda9cec4SJosh Poimboeuf 				goto invalid_relocation;
178*88fc078aSPeter Zijlstra 			write(loc, &val, 4);
1790fdc83b9SAmerigo Wang 			if ((s64)val != *(s32 *)loc)
1800fdc83b9SAmerigo Wang 				goto overflow;
1810fdc83b9SAmerigo Wang 			break;
1820fdc83b9SAmerigo Wang 		case R_X86_64_PC32:
183b21ebf2fSH.J. Lu 		case R_X86_64_PLT32:
184eda9cec4SJosh Poimboeuf 			if (*(u32 *)loc != 0)
185eda9cec4SJosh Poimboeuf 				goto invalid_relocation;
1860fdc83b9SAmerigo Wang 			val -= (u64)loc;
187*88fc078aSPeter Zijlstra 			write(loc, &val, 4);
1880fdc83b9SAmerigo Wang #if 0
1890fdc83b9SAmerigo Wang 			if ((s64)val != *(s32 *)loc)
1900fdc83b9SAmerigo Wang 				goto overflow;
1910fdc83b9SAmerigo Wang #endif
1920fdc83b9SAmerigo Wang 			break;
193b40a142bSArd Biesheuvel 		case R_X86_64_PC64:
194b40a142bSArd Biesheuvel 			if (*(u64 *)loc != 0)
195b40a142bSArd Biesheuvel 				goto invalid_relocation;
196b40a142bSArd Biesheuvel 			val -= (u64)loc;
197*88fc078aSPeter Zijlstra 			write(loc, &val, 8);
198b40a142bSArd Biesheuvel 			break;
1990fdc83b9SAmerigo Wang 		default:
200c767a54bSJoe Perches 			pr_err("%s: Unknown rela relocation: %llu\n",
2010fdc83b9SAmerigo Wang 			       me->name, ELF64_R_TYPE(rel[i].r_info));
2020fdc83b9SAmerigo Wang 			return -ENOEXEC;
2030fdc83b9SAmerigo Wang 		}
2040fdc83b9SAmerigo Wang 	}
2050fdc83b9SAmerigo Wang 	return 0;
2060fdc83b9SAmerigo Wang 
207eda9cec4SJosh Poimboeuf invalid_relocation:
208eda9cec4SJosh Poimboeuf 	pr_err("x86/modules: Skipping invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n",
209eda9cec4SJosh Poimboeuf 	       (int)ELF64_R_TYPE(rel[i].r_info), loc, val);
210eda9cec4SJosh Poimboeuf 	return -ENOEXEC;
211eda9cec4SJosh Poimboeuf 
2120fdc83b9SAmerigo Wang overflow:
213c767a54bSJoe Perches 	pr_err("overflow in relocation type %d val %Lx\n",
2140fdc83b9SAmerigo Wang 	       (int)ELF64_R_TYPE(rel[i].r_info), val);
215c767a54bSJoe Perches 	pr_err("`%s' likely not compiled with -mcmodel=kernel\n",
2160fdc83b9SAmerigo Wang 	       me->name);
2170fdc83b9SAmerigo Wang 	return -ENOEXEC;
2180fdc83b9SAmerigo Wang }
219*88fc078aSPeter Zijlstra 
220*88fc078aSPeter Zijlstra int apply_relocate_add(Elf64_Shdr *sechdrs,
221*88fc078aSPeter Zijlstra 		   const char *strtab,
222*88fc078aSPeter Zijlstra 		   unsigned int symindex,
223*88fc078aSPeter Zijlstra 		   unsigned int relsec,
224*88fc078aSPeter Zijlstra 		   struct module *me)
225*88fc078aSPeter Zijlstra {
226*88fc078aSPeter Zijlstra 	int ret;
227*88fc078aSPeter Zijlstra 	bool early = me->state == MODULE_STATE_UNFORMED;
228*88fc078aSPeter Zijlstra 	void *(*write)(void *, const void *, size_t) = memcpy;
229*88fc078aSPeter Zijlstra 
230*88fc078aSPeter Zijlstra 	if (!early)
231*88fc078aSPeter Zijlstra 		write = text_poke;
232*88fc078aSPeter Zijlstra 
233*88fc078aSPeter Zijlstra 	ret = __apply_relocate_add(sechdrs, strtab, symindex, relsec, me,
234*88fc078aSPeter Zijlstra 				   write);
235*88fc078aSPeter Zijlstra 
236*88fc078aSPeter Zijlstra 	if (!early)
237*88fc078aSPeter Zijlstra 		text_poke_sync();
238*88fc078aSPeter Zijlstra 
239*88fc078aSPeter Zijlstra 	return ret;
240*88fc078aSPeter Zijlstra }
241*88fc078aSPeter Zijlstra 
2420fdc83b9SAmerigo Wang #endif
2430fdc83b9SAmerigo Wang 
2442d5bf28fSAmerigo Wang int module_finalize(const Elf_Ehdr *hdr,
2452d5bf28fSAmerigo Wang 		    const Elf_Shdr *sechdrs,
2462d5bf28fSAmerigo Wang 		    struct module *me)
2472d5bf28fSAmerigo Wang {
2482d5bf28fSAmerigo Wang 	const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
249ee9f8fceSJosh Poimboeuf 		*para = NULL, *orc = NULL, *orc_ip = NULL;
2502d5bf28fSAmerigo Wang 	char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
2512d5bf28fSAmerigo Wang 
2522d5bf28fSAmerigo Wang 	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
2532d5bf28fSAmerigo Wang 		if (!strcmp(".text", secstrings + s->sh_name))
2542d5bf28fSAmerigo Wang 			text = s;
2552d5bf28fSAmerigo Wang 		if (!strcmp(".altinstructions", secstrings + s->sh_name))
2562d5bf28fSAmerigo Wang 			alt = s;
2572d5bf28fSAmerigo Wang 		if (!strcmp(".smp_locks", secstrings + s->sh_name))
2582d5bf28fSAmerigo Wang 			locks = s;
2592d5bf28fSAmerigo Wang 		if (!strcmp(".parainstructions", secstrings + s->sh_name))
2602d5bf28fSAmerigo Wang 			para = s;
261ee9f8fceSJosh Poimboeuf 		if (!strcmp(".orc_unwind", secstrings + s->sh_name))
262ee9f8fceSJosh Poimboeuf 			orc = s;
263ee9f8fceSJosh Poimboeuf 		if (!strcmp(".orc_unwind_ip", secstrings + s->sh_name))
264ee9f8fceSJosh Poimboeuf 			orc_ip = s;
2652d5bf28fSAmerigo Wang 	}
2662d5bf28fSAmerigo Wang 
2672d5bf28fSAmerigo Wang 	if (alt) {
2682d5bf28fSAmerigo Wang 		/* patch .altinstructions */
2692d5bf28fSAmerigo Wang 		void *aseg = (void *)alt->sh_addr;
2702d5bf28fSAmerigo Wang 		apply_alternatives(aseg, aseg + alt->sh_size);
2712d5bf28fSAmerigo Wang 	}
2722d5bf28fSAmerigo Wang 	if (locks && text) {
2732d5bf28fSAmerigo Wang 		void *lseg = (void *)locks->sh_addr;
2742d5bf28fSAmerigo Wang 		void *tseg = (void *)text->sh_addr;
2752d5bf28fSAmerigo Wang 		alternatives_smp_module_add(me, me->name,
2762d5bf28fSAmerigo Wang 					    lseg, lseg + locks->sh_size,
2772d5bf28fSAmerigo Wang 					    tseg, tseg + text->sh_size);
2782d5bf28fSAmerigo Wang 	}
2792d5bf28fSAmerigo Wang 
2802d5bf28fSAmerigo Wang 	if (para) {
2812d5bf28fSAmerigo Wang 		void *pseg = (void *)para->sh_addr;
2822d5bf28fSAmerigo Wang 		apply_paravirt(pseg, pseg + para->sh_size);
2832d5bf28fSAmerigo Wang 	}
2842d5bf28fSAmerigo Wang 
285d9f5ab7bSJason Baron 	/* make jump label nops */
286d9f5ab7bSJason Baron 	jump_label_apply_nops(me);
287d9f5ab7bSJason Baron 
288ee9f8fceSJosh Poimboeuf 	if (orc && orc_ip)
289ee9f8fceSJosh Poimboeuf 		unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size,
290ee9f8fceSJosh Poimboeuf 				   (void *)orc->sh_addr, orc->sh_size);
291ee9f8fceSJosh Poimboeuf 
2925336377dSLinus Torvalds 	return 0;
2932d5bf28fSAmerigo Wang }
2942d5bf28fSAmerigo Wang 
2952d5bf28fSAmerigo Wang void module_arch_cleanup(struct module *mod)
2962d5bf28fSAmerigo Wang {
2972d5bf28fSAmerigo Wang 	alternatives_smp_module_del(mod);
2982d5bf28fSAmerigo Wang }
299