forked from mirrors/linux
		
	module: handle ppc64 relocating kcrctabs when CONFIG_RELOCATABLE=y
powerpc applies relocations to the kcrctab. They're absolute symbols, but it's not completely unreasonable: other archs may too, but the relocation is often 0. http://lists.ozlabs.org/pipermail/linuxppc-dev/2009-November/077972.html Inspired-by: Neil Horman <nhorman@tuxdriver.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Tested-by: Neil Horman <nhorman@tuxdriver.com> Acked-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
		
							parent
							
								
									a8773769d1
								
							
						
					
					
						commit
						d4703aefdb
					
				
					 3 changed files with 29 additions and 7 deletions
				
			
		|  | @ -87,5 +87,10 @@ struct exception_table_entry; | ||||||
| void sort_ex_table(struct exception_table_entry *start, | void sort_ex_table(struct exception_table_entry *start, | ||||||
| 		   struct exception_table_entry *finish); | 		   struct exception_table_entry *finish); | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_MODVERSIONS | ||||||
|  | #define ARCH_RELOCATES_KCRCTAB | ||||||
|  | 
 | ||||||
|  | extern const unsigned long reloc_start[]; | ||||||
|  | #endif | ||||||
| #endif /* __KERNEL__ */ | #endif /* __KERNEL__ */ | ||||||
| #endif	/* _ASM_POWERPC_MODULE_H */ | #endif	/* _ASM_POWERPC_MODULE_H */ | ||||||
|  |  | ||||||
|  | @ -38,6 +38,9 @@ jiffies = jiffies_64 + 4; | ||||||
| #endif | #endif | ||||||
| SECTIONS | SECTIONS | ||||||
| { | { | ||||||
|  | 	. = 0;
 | ||||||
|  | 	reloc_start = .;
 | ||||||
|  | 
 | ||||||
| 	. = KERNELBASE;
 | 	. = KERNELBASE;
 | ||||||
| 
 | 
 | ||||||
| /* | /* | ||||||
|  |  | ||||||
|  | @ -880,11 +880,23 @@ static int try_to_force_load(struct module *mod, const char *reason) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_MODVERSIONS | #ifdef CONFIG_MODVERSIONS | ||||||
|  | /* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */ | ||||||
|  | static unsigned long maybe_relocated(unsigned long crc, | ||||||
|  | 				     const struct module *crc_owner) | ||||||
|  | { | ||||||
|  | #ifdef ARCH_RELOCATES_KCRCTAB | ||||||
|  | 	if (crc_owner == NULL) | ||||||
|  | 		return crc - (unsigned long)reloc_start; | ||||||
|  | #endif | ||||||
|  | 	return crc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int check_version(Elf_Shdr *sechdrs, | static int check_version(Elf_Shdr *sechdrs, | ||||||
| 			 unsigned int versindex, | 			 unsigned int versindex, | ||||||
| 			 const char *symname, | 			 const char *symname, | ||||||
| 			 struct module *mod,  | 			 struct module *mod,  | ||||||
| 			 const unsigned long *crc) | 			 const unsigned long *crc, | ||||||
|  | 			 const struct module *crc_owner) | ||||||
| { | { | ||||||
| 	unsigned int i, num_versions; | 	unsigned int i, num_versions; | ||||||
| 	struct modversion_info *versions; | 	struct modversion_info *versions; | ||||||
|  | @ -905,10 +917,10 @@ static int check_version(Elf_Shdr *sechdrs, | ||||||
| 		if (strcmp(versions[i].name, symname) != 0) | 		if (strcmp(versions[i].name, symname) != 0) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		if (versions[i].crc == *crc) | 		if (versions[i].crc == maybe_relocated(*crc, crc_owner)) | ||||||
| 			return 1; | 			return 1; | ||||||
| 		DEBUGP("Found checksum %lX vs module %lX\n", | 		DEBUGP("Found checksum %lX vs module %lX\n", | ||||||
| 		       *crc, versions[i].crc); | 		       maybe_relocated(*crc, crc_owner), versions[i].crc); | ||||||
| 		goto bad_version; | 		goto bad_version; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -931,7 +943,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs, | ||||||
| 	if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL, | 	if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL, | ||||||
| 			 &crc, true, false)) | 			 &crc, true, false)) | ||||||
| 		BUG(); | 		BUG(); | ||||||
| 	return check_version(sechdrs, versindex, "module_layout", mod, crc); | 	return check_version(sechdrs, versindex, "module_layout", mod, crc, | ||||||
|  | 			     NULL); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* First part is kernel version, which we ignore if module has crcs. */ | /* First part is kernel version, which we ignore if module has crcs. */ | ||||||
|  | @ -949,7 +962,8 @@ static inline int check_version(Elf_Shdr *sechdrs, | ||||||
| 				unsigned int versindex, | 				unsigned int versindex, | ||||||
| 				const char *symname, | 				const char *symname, | ||||||
| 				struct module *mod,  | 				struct module *mod,  | ||||||
| 				const unsigned long *crc) | 				const unsigned long *crc, | ||||||
|  | 				const struct module *crc_owner) | ||||||
| { | { | ||||||
| 	return 1; | 	return 1; | ||||||
| } | } | ||||||
|  | @ -984,8 +998,8 @@ static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs, | ||||||
| 	/* use_module can fail due to OOM,
 | 	/* use_module can fail due to OOM,
 | ||||||
| 	   or module initialization or unloading */ | 	   or module initialization or unloading */ | ||||||
| 	if (sym) { | 	if (sym) { | ||||||
| 		if (!check_version(sechdrs, versindex, name, mod, crc) || | 		if (!check_version(sechdrs, versindex, name, mod, crc, owner) | ||||||
| 		    !use_module(mod, owner)) | 		    || !use_module(mod, owner)) | ||||||
| 			sym = NULL; | 			sym = NULL; | ||||||
| 	} | 	} | ||||||
| 	return sym; | 	return sym; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Rusty Russell
						Rusty Russell