module: refactor load_module part 5
1) Extract out the relocation loop into apply_relocations 2) Extract license and version checks into check_module_license_and_versions 3) Extract icache flushing into flush_module_icache 4) Move __obsparm warning into find_module_sections 5) Move license setting into check_modinfo. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
		
					parent
					
						
							
								9f85a4bbb1
							
						
					
				
			
			
				commit
				
					
						22e268ebec
					
				
			
		
					 1 changed files with 106 additions and 76 deletions
				
			
		
							
								
								
									
										178
									
								
								kernel/module.c
									
										
									
									
									
								
							
							
						
						
									
										178
									
								
								kernel/module.c
									
										
									
									
									
								
							| 
						 | 
					@ -1698,6 +1698,39 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int apply_relocations(struct module *mod,
 | 
				
			||||||
 | 
								     Elf_Ehdr *hdr,
 | 
				
			||||||
 | 
								     Elf_Shdr *sechdrs,
 | 
				
			||||||
 | 
								     unsigned int symindex,
 | 
				
			||||||
 | 
								     unsigned int strindex)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						int err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Now do relocations. */
 | 
				
			||||||
 | 
						for (i = 1; i < hdr->e_shnum; i++) {
 | 
				
			||||||
 | 
							const char *strtab = (char *)sechdrs[strindex].sh_addr;
 | 
				
			||||||
 | 
							unsigned int info = sechdrs[i].sh_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Not a valid relocation section? */
 | 
				
			||||||
 | 
							if (info >= hdr->e_shnum)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Don't bother with non-allocated sections */
 | 
				
			||||||
 | 
							if (!(sechdrs[info].sh_flags & SHF_ALLOC))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (sechdrs[i].sh_type == SHT_REL)
 | 
				
			||||||
 | 
								err = apply_relocate(sechdrs, strtab, symindex, i, mod);
 | 
				
			||||||
 | 
							else if (sechdrs[i].sh_type == SHT_RELA)
 | 
				
			||||||
 | 
								err = apply_relocate_add(sechdrs, strtab, symindex, i,
 | 
				
			||||||
 | 
											 mod);
 | 
				
			||||||
 | 
							if (err < 0)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Additional bytes needed by arch in front of individual sections */
 | 
					/* Additional bytes needed by arch in front of individual sections */
 | 
				
			||||||
unsigned int __weak arch_mod_section_prepend(struct module *mod,
 | 
					unsigned int __weak arch_mod_section_prepend(struct module *mod,
 | 
				
			||||||
					     unsigned int section)
 | 
										     unsigned int section)
 | 
				
			||||||
| 
						 | 
					@ -2179,6 +2212,10 @@ static int check_modinfo(struct module *mod,
 | 
				
			||||||
		       " the quality is unknown, you have been warned.\n",
 | 
							       " the quality is unknown, you have been warned.\n",
 | 
				
			||||||
		       mod->name);
 | 
							       mod->name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Set up license info based on the info section */
 | 
				
			||||||
 | 
						set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2245,6 +2282,10 @@ static void find_module_sections(struct module *mod, Elf_Ehdr *hdr,
 | 
				
			||||||
					     sizeof(*mod->ftrace_callsites),
 | 
										     sizeof(*mod->ftrace_callsites),
 | 
				
			||||||
					     &mod->num_ftrace_callsites);
 | 
										     &mod->num_ftrace_callsites);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (section_addr(hdr, sechdrs, secstrings, "__obsparm"))
 | 
				
			||||||
 | 
							printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
 | 
				
			||||||
 | 
							       mod->name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct module *move_module(struct module *mod,
 | 
					static struct module *move_module(struct module *mod,
 | 
				
			||||||
| 
						 | 
					@ -2311,6 +2352,60 @@ static struct module *move_module(struct module *mod,
 | 
				
			||||||
	return mod;
 | 
						return mod;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int check_module_license_and_versions(struct module *mod,
 | 
				
			||||||
 | 
										     Elf_Shdr *sechdrs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * ndiswrapper is under GPL by itself, but loads proprietary modules.
 | 
				
			||||||
 | 
						 * Don't use add_taint_module(), as it would prevent ndiswrapper from
 | 
				
			||||||
 | 
						 * using GPL-only symbols it needs.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (strcmp(mod->name, "ndiswrapper") == 0)
 | 
				
			||||||
 | 
							add_taint(TAINT_PROPRIETARY_MODULE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* driverloader was caught wrongly pretending to be under GPL */
 | 
				
			||||||
 | 
						if (strcmp(mod->name, "driverloader") == 0)
 | 
				
			||||||
 | 
							add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_MODVERSIONS
 | 
				
			||||||
 | 
						if ((mod->num_syms && !mod->crcs)
 | 
				
			||||||
 | 
						    || (mod->num_gpl_syms && !mod->gpl_crcs)
 | 
				
			||||||
 | 
						    || (mod->num_gpl_future_syms && !mod->gpl_future_crcs)
 | 
				
			||||||
 | 
					#ifdef CONFIG_UNUSED_SYMBOLS
 | 
				
			||||||
 | 
						    || (mod->num_unused_syms && !mod->unused_crcs)
 | 
				
			||||||
 | 
						    || (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							) {
 | 
				
			||||||
 | 
							return try_to_force_load(mod,
 | 
				
			||||||
 | 
										 "no versions for exported symbols");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void flush_module_icache(const struct module *mod)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						mm_segment_t old_fs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* flush the icache in correct context */
 | 
				
			||||||
 | 
						old_fs = get_fs();
 | 
				
			||||||
 | 
						set_fs(KERNEL_DS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Flush the instruction cache, since we've played with text.
 | 
				
			||||||
 | 
						 * Do it before processing of module parameters, so the module
 | 
				
			||||||
 | 
						 * can provide parameter accessor functions of its own.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (mod->module_init)
 | 
				
			||||||
 | 
							flush_icache_range((unsigned long)mod->module_init,
 | 
				
			||||||
 | 
									   (unsigned long)mod->module_init
 | 
				
			||||||
 | 
									   + mod->init_size);
 | 
				
			||||||
 | 
						flush_icache_range((unsigned long)mod->module_core,
 | 
				
			||||||
 | 
								   (unsigned long)mod->module_core + mod->core_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						set_fs(old_fs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Allocate and load the module: note that size of section 0 is always
 | 
					/* Allocate and load the module: note that size of section 0 is always
 | 
				
			||||||
   zero, and we rely on this for optional sections. */
 | 
					   zero, and we rely on this for optional sections. */
 | 
				
			||||||
static noinline struct module *load_module(void __user *umod,
 | 
					static noinline struct module *load_module(void __user *umod,
 | 
				
			||||||
| 
						 | 
					@ -2331,8 +2426,6 @@ static noinline struct module *load_module(void __user *umod,
 | 
				
			||||||
	struct _ddebug *debug = NULL;
 | 
						struct _ddebug *debug = NULL;
 | 
				
			||||||
	unsigned int num_debug = 0;
 | 
						unsigned int num_debug = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mm_segment_t old_fs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
 | 
						DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
 | 
				
			||||||
	       umod, len, uargs);
 | 
						       umod, len, uargs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2453,20 +2546,13 @@ static noinline struct module *load_module(void __user *umod,
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto free_init;
 | 
							goto free_init;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set up license info based on the info section */
 | 
						/* Now we've got everything in the final locations, we can
 | 
				
			||||||
	set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
 | 
						 * find optional sections. */
 | 
				
			||||||
 | 
						find_module_sections(mod, hdr, sechdrs, secstrings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						err = check_module_license_and_versions(mod, sechdrs);
 | 
				
			||||||
	 * ndiswrapper is under GPL by itself, but loads proprietary modules.
 | 
						if (err)
 | 
				
			||||||
	 * Don't use add_taint_module(), as it would prevent ndiswrapper from
 | 
							goto free_unload;
 | 
				
			||||||
	 * using GPL-only symbols it needs.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (strcmp(mod->name, "ndiswrapper") == 0)
 | 
					 | 
				
			||||||
		add_taint(TAINT_PROPRIETARY_MODULE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* driverloader was caught wrongly pretending to be under GPL */
 | 
					 | 
				
			||||||
	if (strcmp(mod->name, "driverloader") == 0)
 | 
					 | 
				
			||||||
		add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set up MODINFO_ATTR fields */
 | 
						/* Set up MODINFO_ATTR fields */
 | 
				
			||||||
	setup_modinfo(mod, sechdrs, infoindex);
 | 
						setup_modinfo(mod, sechdrs, infoindex);
 | 
				
			||||||
| 
						 | 
					@ -2477,47 +2563,9 @@ static noinline struct module *load_module(void __user *umod,
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		goto cleanup;
 | 
							goto cleanup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Now we've got everything in the final locations, we can
 | 
						err = apply_relocations(mod, hdr, sechdrs, symindex, strindex);
 | 
				
			||||||
	 * find optional sections. */
 | 
					 | 
				
			||||||
	find_module_sections(mod, hdr, sechdrs, secstrings);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_MODVERSIONS
 | 
					 | 
				
			||||||
	if ((mod->num_syms && !mod->crcs)
 | 
					 | 
				
			||||||
	    || (mod->num_gpl_syms && !mod->gpl_crcs)
 | 
					 | 
				
			||||||
	    || (mod->num_gpl_future_syms && !mod->gpl_future_crcs)
 | 
					 | 
				
			||||||
#ifdef CONFIG_UNUSED_SYMBOLS
 | 
					 | 
				
			||||||
	    || (mod->num_unused_syms && !mod->unused_crcs)
 | 
					 | 
				
			||||||
	    || (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
		) {
 | 
					 | 
				
			||||||
		err = try_to_force_load(mod,
 | 
					 | 
				
			||||||
					"no versions for exported symbols");
 | 
					 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			goto cleanup;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Now do relocations. */
 | 
					 | 
				
			||||||
	for (i = 1; i < hdr->e_shnum; i++) {
 | 
					 | 
				
			||||||
		const char *strtab = (char *)sechdrs[strindex].sh_addr;
 | 
					 | 
				
			||||||
		unsigned int info = sechdrs[i].sh_info;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Not a valid relocation section? */
 | 
					 | 
				
			||||||
		if (info >= hdr->e_shnum)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Don't bother with non-allocated sections */
 | 
					 | 
				
			||||||
		if (!(sechdrs[info].sh_flags & SHF_ALLOC))
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (sechdrs[i].sh_type == SHT_REL)
 | 
					 | 
				
			||||||
			err = apply_relocate(sechdrs, strtab, symindex, i,mod);
 | 
					 | 
				
			||||||
		else if (sechdrs[i].sh_type == SHT_RELA)
 | 
					 | 
				
			||||||
			err = apply_relocate_add(sechdrs, strtab, symindex, i,
 | 
					 | 
				
			||||||
						 mod);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		goto cleanup;
 | 
							goto cleanup;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  	/* Set up and sort exception table */
 | 
					  	/* Set up and sort exception table */
 | 
				
			||||||
	mod->extable = section_objs(hdr, sechdrs, secstrings, "__ex_table",
 | 
						mod->extable = section_objs(hdr, sechdrs, secstrings, "__ex_table",
 | 
				
			||||||
| 
						 | 
					@ -2541,28 +2589,9 @@ static noinline struct module *load_module(void __user *umod,
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		goto cleanup;
 | 
							goto cleanup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* flush the icache in correct context */
 | 
						flush_module_icache(mod);
 | 
				
			||||||
	old_fs = get_fs();
 | 
					 | 
				
			||||||
	set_fs(KERNEL_DS);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Flush the instruction cache, since we've played with text.
 | 
					 | 
				
			||||||
	 * Do it before processing of module parameters, so the module
 | 
					 | 
				
			||||||
	 * can provide parameter accessor functions of its own.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (mod->module_init)
 | 
					 | 
				
			||||||
		flush_icache_range((unsigned long)mod->module_init,
 | 
					 | 
				
			||||||
				   (unsigned long)mod->module_init
 | 
					 | 
				
			||||||
				   + mod->init_size);
 | 
					 | 
				
			||||||
	flush_icache_range((unsigned long)mod->module_core,
 | 
					 | 
				
			||||||
			   (unsigned long)mod->module_core + mod->core_size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	set_fs(old_fs);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mod->args = args;
 | 
						mod->args = args;
 | 
				
			||||||
	if (section_addr(hdr, sechdrs, secstrings, "__obsparm"))
 | 
					 | 
				
			||||||
		printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
 | 
					 | 
				
			||||||
		       mod->name);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Now sew it into the lists so we can get lockdep and oops
 | 
						/* Now sew it into the lists so we can get lockdep and oops
 | 
				
			||||||
	 * info during argument parsing.  Noone should access us, since
 | 
						 * info during argument parsing.  Noone should access us, since
 | 
				
			||||||
| 
						 | 
					@ -2619,6 +2648,7 @@ static noinline struct module *load_module(void __user *umod,
 | 
				
			||||||
	module_arch_cleanup(mod);
 | 
						module_arch_cleanup(mod);
 | 
				
			||||||
 cleanup:
 | 
					 cleanup:
 | 
				
			||||||
	free_modinfo(mod);
 | 
						free_modinfo(mod);
 | 
				
			||||||
 | 
					 free_unload:
 | 
				
			||||||
	module_unload_free(mod);
 | 
						module_unload_free(mod);
 | 
				
			||||||
 free_init:
 | 
					 free_init:
 | 
				
			||||||
	module_free(mod, mod->module_init);
 | 
						module_free(mod, mod->module_init);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue