diff options
Diffstat (limited to 'arch/x86/kernel/module.c')
| -rw-r--r-- | arch/x86/kernel/module.c | 120 | 
1 files changed, 61 insertions, 59 deletions
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index 8f295609173..e69f9882bf9 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -15,6 +15,9 @@      along with this program; if not, write to the Free Software      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <linux/moduleloader.h>  #include <linux/elf.h>  #include <linux/vmalloc.h> @@ -24,49 +27,70 @@  #include <linux/bug.h>  #include <linux/mm.h>  #include <linux/gfp.h> +#include <linux/jump_label.h> +#include <linux/random.h> -#include <asm/system.h>  #include <asm/page.h>  #include <asm/pgtable.h>  #if 0 -#define DEBUGP printk +#define DEBUGP(fmt, ...)				\ +	printk(KERN_DEBUG fmt, ##__VA_ARGS__)  #else -#define DEBUGP(fmt...) +#define DEBUGP(fmt, ...)				\ +do {							\ +	if (0)						\ +		printk(KERN_DEBUG fmt, ##__VA_ARGS__);	\ +} while (0)  #endif -void *module_alloc(unsigned long size) -{ -	struct vm_struct *area; - -	if (!size) -		return NULL; -	size = PAGE_ALIGN(size); -	if (size > MODULES_LEN) -		return NULL; +#ifdef CONFIG_RANDOMIZE_BASE +static unsigned long module_load_offset; +static int randomize_modules = 1; -	area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END); -	if (!area) -		return NULL; +/* Mutex protects the module_load_offset. */ +static DEFINE_MUTEX(module_kaslr_mutex); -	return __vmalloc_area(area, GFP_KERNEL | __GFP_HIGHMEM, -					PAGE_KERNEL_EXEC); +static int __init parse_nokaslr(char *p) +{ +	randomize_modules = 0; +	return 0;  } +early_param("nokaslr", parse_nokaslr); -/* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) +static unsigned long int get_module_load_offset(void)  { -	vfree(module_region); +	if (randomize_modules) { +		mutex_lock(&module_kaslr_mutex); +		/* +		 * Calculate the module_load_offset the first time this +		 * code is called. Once calculated it stays the same until +		 * reboot. +		 */ +		if (module_load_offset == 0) +			module_load_offset = +				(get_random_int() % 1024 + 1) * PAGE_SIZE; +		mutex_unlock(&module_kaslr_mutex); +	} +	return module_load_offset;  } - -/* We don't need anything special. */ -int module_frob_arch_sections(Elf_Ehdr *hdr, -			      Elf_Shdr *sechdrs, -			      char *secstrings, -			      struct module *mod) +#else +static unsigned long int get_module_load_offset(void)  {  	return 0;  } +#endif + +void *module_alloc(unsigned long size) +{ +	if (PAGE_ALIGN(size) > MODULES_LEN) +		return NULL; +	return __vmalloc_node_range(size, 1, +				    MODULES_VADDR + get_module_load_offset(), +				    MODULES_END, GFP_KERNEL | __GFP_HIGHMEM, +				    PAGE_KERNEL_EXEC, NUMA_NO_NODE, +				    __builtin_return_address(0)); +}  #ifdef CONFIG_X86_32  int apply_relocate(Elf32_Shdr *sechdrs, @@ -80,8 +104,8 @@ int apply_relocate(Elf32_Shdr *sechdrs,  	Elf32_Sym *sym;  	uint32_t *location; -	DEBUGP("Applying relocate section %u to %u\n", relsec, -	       sechdrs[relsec].sh_info); +	DEBUGP("Applying relocate section %u to %u\n", +	       relsec, sechdrs[relsec].sh_info);  	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {  		/* This is where to make the change */  		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr @@ -97,28 +121,17 @@ int apply_relocate(Elf32_Shdr *sechdrs,  			*location += sym->st_value;  			break;  		case R_386_PC32: -			/* Add the value, subtract its postition */ +			/* Add the value, subtract its position */  			*location += sym->st_value - (uint32_t)location;  			break;  		default: -			printk(KERN_ERR "module %s: Unknown relocation: %u\n", +			pr_err("%s: Unknown relocation: %u\n",  			       me->name, ELF32_R_TYPE(rel[i].r_info));  			return -ENOEXEC;  		}  	}  	return 0;  } - -int apply_relocate_add(Elf32_Shdr *sechdrs, -		       const char *strtab, -		       unsigned int symindex, -		       unsigned int relsec, -		       struct module *me) -{ -	printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", -	       me->name); -	return -ENOEXEC; -}  #else /*X86_64*/  int apply_relocate_add(Elf64_Shdr *sechdrs,  		   const char *strtab, @@ -132,8 +145,8 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,  	void *loc;  	u64 val; -	DEBUGP("Applying relocate section %u to %u\n", relsec, -	       sechdrs[relsec].sh_info); +	DEBUGP("Applying relocate section %u to %u\n", +	       relsec, sechdrs[relsec].sh_info);  	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {  		/* This is where to make the change */  		loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr @@ -145,8 +158,8 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,  			+ ELF64_R_SYM(rel[i].r_info);  		DEBUGP("type %d st_value %Lx r_addend %Lx loc %Lx\n", -			(int)ELF64_R_TYPE(rel[i].r_info), -			sym->st_value, rel[i].r_addend, (u64)loc); +		       (int)ELF64_R_TYPE(rel[i].r_info), +		       sym->st_value, rel[i].r_addend, (u64)loc);  		val = sym->st_value + rel[i].r_addend; @@ -175,7 +188,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,  #endif  			break;  		default: -			printk(KERN_ERR "module %s: Unknown rela relocation: %llu\n", +			pr_err("%s: Unknown rela relocation: %llu\n",  			       me->name, ELF64_R_TYPE(rel[i].r_info));  			return -ENOEXEC;  		} @@ -183,23 +196,12 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,  	return 0;  overflow: -	printk(KERN_ERR "overflow in relocation type %d val %Lx\n", +	pr_err("overflow in relocation type %d val %Lx\n",  	       (int)ELF64_R_TYPE(rel[i].r_info), val); -	printk(KERN_ERR "`%s' likely not compiled with -mcmodel=kernel\n", +	pr_err("`%s' likely not compiled with -mcmodel=kernel\n",  	       me->name);  	return -ENOEXEC;  } - -int apply_relocate(Elf_Shdr *sechdrs, -		   const char *strtab, -		   unsigned int symindex, -		   unsigned int relsec, -		   struct module *me) -{ -	printk(KERN_ERR "non add relocation not supported\n"); -	return -ENOSYS; -} -  #endif  int module_finalize(const Elf_Ehdr *hdr,  | 
