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