| .. | .. | 
|---|
 | 1 | +// SPDX-License-Identifier: GPL-2.0-or-later  | 
|---|
| 1 | 2 |  /*  Kernel module help for x86. | 
|---|
| 2 | 3 |      Copyright (C) 2001 Rusty Russell. | 
|---|
| 3 | 4 |   | 
|---|
| 4 |  | -    This program is free software; you can redistribute it and/or modify  | 
|---|
| 5 |  | -    it under the terms of the GNU General Public License as published by  | 
|---|
| 6 |  | -    the Free Software Foundation; either version 2 of the License, or  | 
|---|
| 7 |  | -    (at your option) any later version.  | 
|---|
| 8 |  | -  | 
|---|
| 9 |  | -    This program is distributed in the hope that it will be useful,  | 
|---|
| 10 |  | -    but WITHOUT ANY WARRANTY; without even the implied warranty of  | 
|---|
| 11 |  | -    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  | 
|---|
| 12 |  | -    GNU General Public License for more details.  | 
|---|
| 13 |  | -  | 
|---|
| 14 |  | -    You should have received a copy of the GNU General Public License  | 
|---|
| 15 |  | -    along with this program; if not, write to the Free Software  | 
|---|
| 16 |  | -    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  | 
|---|
| 17 | 5 |  */ | 
|---|
| 18 | 6 |   | 
|---|
| 19 | 7 |  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 
|---|
| .. | .. | 
|---|
| 30 | 18 |  #include <linux/gfp.h> | 
|---|
| 31 | 19 |  #include <linux/jump_label.h> | 
|---|
| 32 | 20 |  #include <linux/random.h> | 
|---|
 | 21 | +#include <linux/memory.h>  | 
|---|
| 33 | 22 |   | 
|---|
| 34 | 23 |  #include <asm/text-patching.h> | 
|---|
| 35 | 24 |  #include <asm/page.h> | 
|---|
| 36 |  | -#include <asm/pgtable.h>  | 
|---|
| 37 | 25 |  #include <asm/setup.h> | 
|---|
| 38 | 26 |  #include <asm/unwind.h> | 
|---|
| 39 | 27 |   | 
|---|
| .. | .. | 
|---|
| 139 | 127 |  	return 0; | 
|---|
| 140 | 128 |  } | 
|---|
| 141 | 129 |  #else /*X86_64*/ | 
|---|
| 142 |  | -int apply_relocate_add(Elf64_Shdr *sechdrs,  | 
|---|
 | 130 | +static int __apply_relocate_add(Elf64_Shdr *sechdrs,  | 
|---|
| 143 | 131 |  		   const char *strtab, | 
|---|
| 144 | 132 |  		   unsigned int symindex, | 
|---|
| 145 | 133 |  		   unsigned int relsec, | 
|---|
| 146 |  | -		   struct module *me)  | 
|---|
 | 134 | +		   struct module *me,  | 
|---|
 | 135 | +		   void *(*write)(void *dest, const void *src, size_t len))  | 
|---|
| 147 | 136 |  { | 
|---|
| 148 | 137 |  	unsigned int i; | 
|---|
| 149 | 138 |  	Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; | 
|---|
| .. | .. | 
|---|
| 175 | 164 |  		case R_X86_64_64: | 
|---|
| 176 | 165 |  			if (*(u64 *)loc != 0) | 
|---|
| 177 | 166 |  				goto invalid_relocation; | 
|---|
| 178 |  | -			*(u64 *)loc = val;  | 
|---|
 | 167 | +			write(loc, &val, 8);  | 
|---|
| 179 | 168 |  			break; | 
|---|
| 180 | 169 |  		case R_X86_64_32: | 
|---|
| 181 | 170 |  			if (*(u32 *)loc != 0) | 
|---|
| 182 | 171 |  				goto invalid_relocation; | 
|---|
| 183 |  | -			*(u32 *)loc = val;  | 
|---|
 | 172 | +			write(loc, &val, 4);  | 
|---|
| 184 | 173 |  			if (val != *(u32 *)loc) | 
|---|
| 185 | 174 |  				goto overflow; | 
|---|
| 186 | 175 |  			break; | 
|---|
| 187 | 176 |  		case R_X86_64_32S: | 
|---|
| 188 | 177 |  			if (*(s32 *)loc != 0) | 
|---|
| 189 | 178 |  				goto invalid_relocation; | 
|---|
| 190 |  | -			*(s32 *)loc = val;  | 
|---|
 | 179 | +			write(loc, &val, 4);  | 
|---|
| 191 | 180 |  			if ((s64)val != *(s32 *)loc) | 
|---|
| 192 | 181 |  				goto overflow; | 
|---|
| 193 | 182 |  			break; | 
|---|
| .. | .. | 
|---|
| 196 | 185 |  			if (*(u32 *)loc != 0) | 
|---|
| 197 | 186 |  				goto invalid_relocation; | 
|---|
| 198 | 187 |  			val -= (u64)loc; | 
|---|
| 199 |  | -			*(u32 *)loc = val;  | 
|---|
 | 188 | +			write(loc, &val, 4);  | 
|---|
| 200 | 189 |  #if 0 | 
|---|
| 201 | 190 |  			if ((s64)val != *(s32 *)loc) | 
|---|
| 202 | 191 |  				goto overflow; | 
|---|
| 203 | 192 |  #endif | 
|---|
 | 193 | +			break;  | 
|---|
 | 194 | +		case R_X86_64_PC64:  | 
|---|
 | 195 | +			if (*(u64 *)loc != 0)  | 
|---|
 | 196 | +				goto invalid_relocation;  | 
|---|
 | 197 | +			val -= (u64)loc;  | 
|---|
 | 198 | +			write(loc, &val, 8);  | 
|---|
| 204 | 199 |  			break; | 
|---|
| 205 | 200 |  		case R_X86_64_8: | 
|---|
| 206 | 201 |  			if (!strncmp(strtab + sym->st_name, "__typeid__", 10)) | 
|---|
| .. | .. | 
|---|
| 226 | 221 |  	       me->name); | 
|---|
| 227 | 222 |  	return -ENOEXEC; | 
|---|
| 228 | 223 |  } | 
|---|
 | 224 | +  | 
|---|
 | 225 | +int apply_relocate_add(Elf64_Shdr *sechdrs,  | 
|---|
 | 226 | +		   const char *strtab,  | 
|---|
 | 227 | +		   unsigned int symindex,  | 
|---|
 | 228 | +		   unsigned int relsec,  | 
|---|
 | 229 | +		   struct module *me)  | 
|---|
 | 230 | +{  | 
|---|
 | 231 | +	int ret;  | 
|---|
 | 232 | +	bool early = me->state == MODULE_STATE_UNFORMED;  | 
|---|
 | 233 | +	void *(*write)(void *, const void *, size_t) = memcpy;  | 
|---|
 | 234 | +  | 
|---|
 | 235 | +	if (!early) {  | 
|---|
 | 236 | +		write = text_poke;  | 
|---|
 | 237 | +		mutex_lock(&text_mutex);  | 
|---|
 | 238 | +	}  | 
|---|
 | 239 | +  | 
|---|
 | 240 | +	ret = __apply_relocate_add(sechdrs, strtab, symindex, relsec, me,  | 
|---|
 | 241 | +				   write);  | 
|---|
 | 242 | +  | 
|---|
 | 243 | +	if (!early) {  | 
|---|
 | 244 | +		text_poke_sync();  | 
|---|
 | 245 | +		mutex_unlock(&text_mutex);  | 
|---|
 | 246 | +	}  | 
|---|
 | 247 | +  | 
|---|
 | 248 | +	return ret;  | 
|---|
 | 249 | +}  | 
|---|
 | 250 | +  | 
|---|
| 229 | 251 |  #endif | 
|---|
| 230 | 252 |   | 
|---|
| 231 | 253 |  int module_finalize(const Elf_Ehdr *hdr, | 
|---|
| .. | .. | 
|---|
| 233 | 255 |  		    struct module *me) | 
|---|
| 234 | 256 |  { | 
|---|
| 235 | 257 |  	const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL, | 
|---|
| 236 |  | -		*para = NULL, *orc = NULL, *orc_ip = NULL;  | 
|---|
 | 258 | +		*para = NULL, *orc = NULL, *orc_ip = NULL,  | 
|---|
 | 259 | +		*retpolines = NULL, *returns = NULL;  | 
|---|
| 237 | 260 |  	char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | 
|---|
| 238 | 261 |   | 
|---|
| 239 | 262 |  	for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { | 
|---|
| .. | .. | 
|---|
| 249 | 272 |  			orc = s; | 
|---|
| 250 | 273 |  		if (!strcmp(".orc_unwind_ip", secstrings + s->sh_name)) | 
|---|
| 251 | 274 |  			orc_ip = s; | 
|---|
 | 275 | +		if (!strcmp(".retpoline_sites", secstrings + s->sh_name))  | 
|---|
 | 276 | +			retpolines = s;  | 
|---|
 | 277 | +		if (!strcmp(".return_sites", secstrings + s->sh_name))  | 
|---|
 | 278 | +			returns = s;  | 
|---|
| 252 | 279 |  	} | 
|---|
| 253 | 280 |   | 
|---|
 | 281 | +	if (retpolines) {  | 
|---|
 | 282 | +		void *rseg = (void *)retpolines->sh_addr;  | 
|---|
 | 283 | +		apply_retpolines(rseg, rseg + retpolines->sh_size);  | 
|---|
 | 284 | +	}  | 
|---|
 | 285 | +	if (returns) {  | 
|---|
 | 286 | +		void *rseg = (void *)returns->sh_addr;  | 
|---|
 | 287 | +		apply_returns(rseg, rseg + returns->sh_size);  | 
|---|
 | 288 | +	}  | 
|---|
| 254 | 289 |  	if (alt) { | 
|---|
| 255 | 290 |  		/* patch .altinstructions */ | 
|---|
| 256 | 291 |  		void *aseg = (void *)alt->sh_addr; | 
|---|