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