xref: /linux/arch/x86/kernel/module.c (revision 547c5775a742d9c83891b629b75d1d4c8e88d8c0)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*  Kernel module help for x86.
3     Copyright (C) 2001 Rusty Russell.
4 
5 */
6 
7 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8 
9 #include <linux/moduleloader.h>
10 #include <linux/elf.h>
11 #include <linux/vmalloc.h>
12 #include <linux/fs.h>
13 #include <linux/string.h>
14 #include <linux/kernel.h>
15 #include <linux/kasan.h>
16 #include <linux/bug.h>
17 #include <linux/mm.h>
18 #include <linux/gfp.h>
19 #include <linux/jump_label.h>
20 #include <linux/random.h>
21 #include <linux/memory.h>
22 #include <linux/stackprotector.h>
23 
24 #include <asm/text-patching.h>
25 #include <asm/page.h>
26 #include <asm/setup.h>
27 #include <asm/unwind.h>
28 
29 #if 0
30 #define DEBUGP(fmt, ...)				\
31 	printk(KERN_DEBUG fmt, ##__VA_ARGS__)
32 #else
33 #define DEBUGP(fmt, ...)				\
34 do {							\
35 	if (0)						\
36 		printk(KERN_DEBUG fmt, ##__VA_ARGS__);	\
37 } while (0)
38 #endif
39 
40 #ifdef CONFIG_X86_32
apply_relocate(Elf32_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * me)41 int apply_relocate(Elf32_Shdr *sechdrs,
42 		   const char *strtab,
43 		   unsigned int symindex,
44 		   unsigned int relsec,
45 		   struct module *me)
46 {
47 	unsigned int i;
48 	Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
49 	Elf32_Sym *sym;
50 	uint32_t *location;
51 
52 	DEBUGP("Applying relocate section %u to %u\n",
53 	       relsec, sechdrs[relsec].sh_info);
54 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
55 		/* This is where to make the change */
56 		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
57 			+ rel[i].r_offset;
58 		/* This is the symbol it is referring to.  Note that all
59 		   undefined symbols have been resolved.  */
60 		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
61 			+ ELF32_R_SYM(rel[i].r_info);
62 
63 		switch (ELF32_R_TYPE(rel[i].r_info)) {
64 		case R_386_32:
65 			/* We add the value into the location given */
66 			*location += sym->st_value;
67 			break;
68 		case R_386_PC32:
69 		case R_386_PLT32:
70 			/* Add the value, subtract its position */
71 			*location += sym->st_value - (uint32_t)location;
72 			break;
73 		default:
74 			pr_err("%s: Unknown relocation: %u\n",
75 			       me->name, ELF32_R_TYPE(rel[i].r_info));
76 			return -ENOEXEC;
77 		}
78 	}
79 	return 0;
80 }
81 #else /*X86_64*/
__write_relocate_add(Elf64_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * me,void * (* write)(void * dest,const void * src,size_t len),bool apply)82 static int __write_relocate_add(Elf64_Shdr *sechdrs,
83 		   const char *strtab,
84 		   unsigned int symindex,
85 		   unsigned int relsec,
86 		   struct module *me,
87 		   void *(*write)(void *dest, const void *src, size_t len),
88 		   bool apply)
89 {
90 	unsigned int i;
91 	Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
92 	Elf64_Sym *sym;
93 	void *loc;
94 	u64 val;
95 	u64 zero = 0ULL;
96 
97 	DEBUGP("%s relocate section %u to %u\n",
98 	       apply ? "Applying" : "Clearing",
99 	       relsec, sechdrs[relsec].sh_info);
100 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
101 		size_t size;
102 
103 		/* This is where to make the change */
104 		loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
105 			+ rel[i].r_offset;
106 
107 		/* This is the symbol it is referring to.  Note that all
108 		   undefined symbols have been resolved.  */
109 		sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
110 			+ ELF64_R_SYM(rel[i].r_info);
111 
112 		DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n",
113 		       (int)ELF64_R_TYPE(rel[i].r_info),
114 		       sym->st_value, rel[i].r_addend, (u64)loc);
115 
116 		val = sym->st_value + rel[i].r_addend;
117 
118 		switch (ELF64_R_TYPE(rel[i].r_info)) {
119 		case R_X86_64_NONE:
120 			continue;  /* nothing to write */
121 		case R_X86_64_64:
122 			size = 8;
123 			break;
124 		case R_X86_64_32:
125 			if (val != *(u32 *)&val)
126 				goto overflow;
127 			size = 4;
128 			break;
129 		case R_X86_64_32S:
130 			if ((s64)val != *(s32 *)&val)
131 				goto overflow;
132 			size = 4;
133 			break;
134 #if defined(CONFIG_STACKPROTECTOR) && \
135     defined(CONFIG_CC_IS_CLANG) && CONFIG_CLANG_VERSION < 170000
136 		case R_X86_64_REX_GOTPCRELX: {
137 			static unsigned long __percpu *const addr = &__stack_chk_guard;
138 
139 			if (sym->st_value != (u64)addr) {
140 				pr_err("%s: Unsupported GOTPCREL relocation\n", me->name);
141 				return -ENOEXEC;
142 			}
143 
144 			val = (u64)&addr + rel[i].r_addend;
145 			fallthrough;
146 		}
147 #endif
148 		case R_X86_64_PC32:
149 		case R_X86_64_PLT32:
150 			val -= (u64)loc;
151 			size = 4;
152 			break;
153 		case R_X86_64_PC64:
154 			val -= (u64)loc;
155 			size = 8;
156 			break;
157 		default:
158 			pr_err("%s: Unknown rela relocation: %llu\n",
159 			       me->name, ELF64_R_TYPE(rel[i].r_info));
160 			return -ENOEXEC;
161 		}
162 
163 		if (apply) {
164 			if (memcmp(loc, &zero, size)) {
165 				pr_err("x86/modules: Invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n",
166 				       (int)ELF64_R_TYPE(rel[i].r_info), loc, val);
167 				return -ENOEXEC;
168 			}
169 			write(loc, &val, size);
170 		} else {
171 			if (memcmp(loc, &val, size)) {
172 				pr_warn("x86/modules: Invalid relocation target, existing value does not match expected value for type %d, loc %p, val %Lx\n",
173 					(int)ELF64_R_TYPE(rel[i].r_info), loc, val);
174 				return -ENOEXEC;
175 			}
176 			write(loc, &zero, size);
177 		}
178 	}
179 	return 0;
180 
181 overflow:
182 	pr_err("overflow in relocation type %d val %Lx\n",
183 	       (int)ELF64_R_TYPE(rel[i].r_info), val);
184 	pr_err("`%s' likely not compiled with -mcmodel=kernel\n",
185 	       me->name);
186 	return -ENOEXEC;
187 }
188 
write_relocate_add(Elf64_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * me,bool apply)189 static int write_relocate_add(Elf64_Shdr *sechdrs,
190 			      const char *strtab,
191 			      unsigned int symindex,
192 			      unsigned int relsec,
193 			      struct module *me,
194 			      bool apply)
195 {
196 	int ret;
197 	bool early = me->state == MODULE_STATE_UNFORMED;
198 	void *(*write)(void *, const void *, size_t) = memcpy;
199 
200 	if (!early) {
201 		write = text_poke;
202 		mutex_lock(&text_mutex);
203 	}
204 
205 	ret = __write_relocate_add(sechdrs, strtab, symindex, relsec, me,
206 				   write, apply);
207 
208 	if (!early) {
209 		smp_text_poke_sync_each_cpu();
210 		mutex_unlock(&text_mutex);
211 	}
212 
213 	return ret;
214 }
215 
apply_relocate_add(Elf64_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * me)216 int apply_relocate_add(Elf64_Shdr *sechdrs,
217 		   const char *strtab,
218 		   unsigned int symindex,
219 		   unsigned int relsec,
220 		   struct module *me)
221 {
222 	return write_relocate_add(sechdrs, strtab, symindex, relsec, me, true);
223 }
224 
225 #ifdef CONFIG_LIVEPATCH
clear_relocate_add(Elf64_Shdr * sechdrs,const char * strtab,unsigned int symindex,unsigned int relsec,struct module * me)226 void clear_relocate_add(Elf64_Shdr *sechdrs,
227 			const char *strtab,
228 			unsigned int symindex,
229 			unsigned int relsec,
230 			struct module *me)
231 {
232 	write_relocate_add(sechdrs, strtab, symindex, relsec, me, false);
233 }
234 #endif
235 
236 #endif
237 
module_finalize(const Elf_Ehdr * hdr,const Elf_Shdr * sechdrs,struct module * me)238 int module_finalize(const Elf_Ehdr *hdr,
239 		    const Elf_Shdr *sechdrs,
240 		    struct module *me)
241 {
242 	const Elf_Shdr *s, *alt = NULL, *locks = NULL,
243 		*orc = NULL, *orc_ip = NULL,
244 		*retpolines = NULL, *returns = NULL, *ibt_endbr = NULL,
245 		*calls = NULL, *cfi = NULL;
246 	char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
247 
248 	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
249 		if (!strcmp(".altinstructions", secstrings + s->sh_name))
250 			alt = s;
251 		if (!strcmp(".smp_locks", secstrings + s->sh_name))
252 			locks = s;
253 		if (!strcmp(".orc_unwind", secstrings + s->sh_name))
254 			orc = s;
255 		if (!strcmp(".orc_unwind_ip", secstrings + s->sh_name))
256 			orc_ip = s;
257 		if (!strcmp(".retpoline_sites", secstrings + s->sh_name))
258 			retpolines = s;
259 		if (!strcmp(".return_sites", secstrings + s->sh_name))
260 			returns = s;
261 		if (!strcmp(".call_sites", secstrings + s->sh_name))
262 			calls = s;
263 		if (!strcmp(".cfi_sites", secstrings + s->sh_name))
264 			cfi = s;
265 		if (!strcmp(".ibt_endbr_seal", secstrings + s->sh_name))
266 			ibt_endbr = s;
267 	}
268 
269 	its_init_mod(me);
270 
271 	if (retpolines || cfi) {
272 		void *rseg = NULL, *cseg = NULL;
273 		unsigned int rsize = 0, csize = 0;
274 
275 		if (retpolines) {
276 			rseg = (void *)retpolines->sh_addr;
277 			rsize = retpolines->sh_size;
278 		}
279 
280 		if (cfi) {
281 			cseg = (void *)cfi->sh_addr;
282 			csize = cfi->sh_size;
283 		}
284 
285 		apply_fineibt(rseg, rseg + rsize, cseg, cseg + csize);
286 	}
287 	if (retpolines) {
288 		void *rseg = (void *)retpolines->sh_addr;
289 		apply_retpolines(rseg, rseg + retpolines->sh_size);
290 	}
291 
292 	its_fini_mod(me);
293 
294 	if (returns) {
295 		void *rseg = (void *)returns->sh_addr;
296 		apply_returns(rseg, rseg + returns->sh_size);
297 	}
298 	if (calls) {
299 		struct callthunk_sites cs = {};
300 
301 		cs.call_start = (void *)calls->sh_addr;
302 		cs.call_end = (void *)calls->sh_addr + calls->sh_size;
303 
304 		callthunks_patch_module_calls(&cs, me);
305 	}
306 	if (alt) {
307 		/* patch .altinstructions */
308 		void *aseg = (void *)alt->sh_addr;
309 		apply_alternatives(aseg, aseg + alt->sh_size);
310 	}
311 	if (ibt_endbr) {
312 		void *iseg = (void *)ibt_endbr->sh_addr;
313 		apply_seal_endbr(iseg, iseg + ibt_endbr->sh_size);
314 	}
315 	if (locks) {
316 		void *lseg = (void *)locks->sh_addr;
317 		void *text = me->mem[MOD_TEXT].base;
318 		void *text_end = text + me->mem[MOD_TEXT].size;
319 		alternatives_smp_module_add(me, me->name,
320 					    lseg, lseg + locks->sh_size,
321 					    text, text_end);
322 	}
323 
324 	if (orc && orc_ip)
325 		unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size,
326 				   (void *)orc->sh_addr, orc->sh_size);
327 
328 	return 0;
329 }
330 
module_arch_cleanup(struct module * mod)331 void module_arch_cleanup(struct module *mod)
332 {
333 	alternatives_smp_module_del(mod);
334 	its_free_mod(mod);
335 }
336