2126 lines · 54.9 KB · C
RawDownload
	obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");	versindex = find_sec(hdr, sechdrs, secstrings, "__versions");	infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo");	pcpuindex = find_pcpusec(hdr, sechdrs, secstrings); 	/* Don't keep modinfo section */	sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;#ifdef CONFIG_KALLSYMS	/* Keep symbol and string tables for decoding later. */	sechdrs[symindex].sh_flags |= SHF_ALLOC;	sechdrs[strindex].sh_flags |= SHF_ALLOC;#endif 	/* Check module struct version now, before we try to use module. */	if (!check_modstruct_version(sechdrs, versindex, mod)) {		err = -ENOEXEC;		goto free_hdr;	} 	modmagic = get_modinfo(sechdrs, infoindex, "vermagic");	/* This is allowed: modprobe --force will invalidate it. */	if (!modmagic) {		add_taint(TAINT_FORCED_MODULE);		printk(KERN_WARNING "%s: no version magic, tainting kernel.\n",		       mod->name);	} else if (!same_magic(modmagic, vermagic)) {		printk(KERN_ERR "%s: version magic '%s' should be '%s'\n",		       mod->name, modmagic, vermagic);		err = -ENOEXEC;		goto free_hdr;	} 	/* Now copy in args */	args = strndup_user(uargs, ~0UL >> 1);	if (IS_ERR(args)) {		err = PTR_ERR(args);		goto free_hdr;	} 	if (find_module(mod->name)) {		err = -EEXIST;		goto free_mod;	} 	mod->state = MODULE_STATE_COMING; 	/* Allow arches to frob section contents and sizes.  */	err = module_frob_arch_sections(hdr, sechdrs, secstrings, mod);	if (err < 0)		goto free_mod; 	if (pcpuindex) {		/* We have a special allocation for this section. */		percpu = percpu_modalloc(sechdrs[pcpuindex].sh_size,					 sechdrs[pcpuindex].sh_addralign,					 mod->name);		if (!percpu) {			err = -ENOMEM;			goto free_mod;		}		sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC;		mod->percpu = percpu;	} 	/* Determine total sizes, and put offsets in sh_entsize.  For now	   this is done generically; there doesn't appear to be any	   special cases for the architectures. */	layout_sections(mod, hdr, sechdrs, secstrings); 	/* Do the allocs. */	ptr = module_alloc(mod->core_size);	if (!ptr) {		err = -ENOMEM;		goto free_percpu;	}	memset(ptr, 0, mod->core_size);	mod->module_core = ptr; 	ptr = module_alloc(mod->init_size);	if (!ptr && mod->init_size) {		err = -ENOMEM;		goto free_core;	}	memset(ptr, 0, mod->init_size);	mod->module_init = ptr; 	/* Transfer each section which specifies SHF_ALLOC */	DEBUGP("final section addresses:\n");	for (i = 0; i < hdr->e_shnum; i++) {		void *dest; 		if (!(sechdrs[i].sh_flags & SHF_ALLOC))			continue; 		if (sechdrs[i].sh_entsize & INIT_OFFSET_MASK)			dest = mod->module_init				+ (sechdrs[i].sh_entsize & ~INIT_OFFSET_MASK);		else			dest = mod->module_core + sechdrs[i].sh_entsize; 		if (sechdrs[i].sh_type != SHT_NOBITS)			memcpy(dest, (void *)sechdrs[i].sh_addr,			       sechdrs[i].sh_size);		/* Update sh_addr to point to copy in image. */		sechdrs[i].sh_addr = (unsigned long)dest;		DEBUGP("\t0x%lx %s\n", sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name);	}	/* Module has been moved. */	mod = (void *)sechdrs[modindex].sh_addr; 	/* Now we've moved module, initialize linked lists, etc. */	module_unload_init(mod); 	/* Set up license info based on the info section */	set_license(mod, get_modinfo(sechdrs, infoindex, "license")); 	if (strcmp(mod->name, "ndiswrapper") == 0)		add_taint(TAINT_PROPRIETARY_MODULE);	if (strcmp(mod->name, "driverloader") == 0)		add_taint(TAINT_PROPRIETARY_MODULE); 	/* Set up MODINFO_ATTR fields */	setup_modinfo(mod, sechdrs, infoindex); 	/* Fix up syms, so that st_value is a pointer to location. */	err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,			       mod);	if (err < 0)		goto cleanup; 	/* Set up EXPORTed & EXPORT_GPLed symbols (section 0 is 0 length) */	mod->num_syms = sechdrs[exportindex].sh_size / sizeof(*mod->syms);	mod->syms = (void *)sechdrs[exportindex].sh_addr;	if (crcindex)		mod->crcs = (void *)sechdrs[crcindex].sh_addr;	mod->num_gpl_syms = sechdrs[gplindex].sh_size / sizeof(*mod->gpl_syms);	mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr;	if (gplcrcindex)		mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;	mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size /					sizeof(*mod->gpl_future_syms);	mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;	if (gplfuturecrcindex)		mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr; #ifdef CONFIG_MODVERSIONS	if ((mod->num_syms && !crcindex) || 	    (mod->num_gpl_syms && !gplcrcindex) ||	    (mod->num_gpl_future_syms && !gplfuturecrcindex)) {		printk(KERN_WARNING "%s: No versions for exported symbols."		       " Tainting kernel.\n", mod->name);		add_taint(TAINT_FORCED_MODULE);	}#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)			goto cleanup;	}         /* Find duplicate symbols */	err = verify_export_symbols(mod); 	if (err < 0)		goto cleanup;   	/* Set up and sort exception table */	mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable);	mod->extable = extable = (void *)sechdrs[exindex].sh_addr;	sort_extable(extable, extable + mod->num_exentries); 	/* Finally, copy percpu area over. */	percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr,		       sechdrs[pcpuindex].sh_size); 	add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); 	err = module_finalize(hdr, sechdrs, mod);	if (err < 0)		goto cleanup; 	/* 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); 	mod->args = args;	if (obsparmindex)		printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",		       mod->name); 	/* Size of section 0 is 0, so this works well if no params */	err = parse_args(mod->name, mod->args,			 (struct kernel_param *)			 sechdrs[setupindex].sh_addr,			 sechdrs[setupindex].sh_size			 / sizeof(struct kernel_param),			 NULL);	if (err < 0)		goto arch_cleanup; 	err = mod_sysfs_setup(mod, 			      (struct kernel_param *)			      sechdrs[setupindex].sh_addr,			      sechdrs[setupindex].sh_size			      / sizeof(struct kernel_param));	if (err < 0)		goto arch_cleanup;	add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); 	/* Get rid of temporary copy */	vfree(hdr); 	/* Done! */	return mod;  arch_cleanup:	module_arch_cleanup(mod); cleanup:	module_unload_free(mod);	module_free(mod, mod->module_init); free_core:	module_free(mod, mod->module_core); free_percpu:	if (percpu)		percpu_modfree(percpu); free_mod:	kfree(args); free_hdr:	vfree(hdr);	return ERR_PTR(err);  truncated:	printk(KERN_ERR "Module len %lu truncated\n", len);	err = -ENOEXEC;	goto free_hdr;} /* * link the module with the whole machine is stopped with interrupts off * - this defends against kallsyms not taking locks */static int __link_module(void *_mod){	struct module *mod = _mod;	list_add(&mod->list, &modules);	return 0;} /* This is where the real work happens */asmlinkage longsys_init_module(void __user *umod,		unsigned long len,		const char __user *uargs){	struct module *mod;	int ret = 0; 	/* Must have permission */	if (!capable(CAP_SYS_MODULE))		return -EPERM; 	/* Only one module load at a time, please */	if (mutex_lock_interruptible(&module_mutex) != 0)		return -EINTR; 	/* Do all the hard work */	mod = load_module(umod, len, uargs);	if (IS_ERR(mod)) {		mutex_unlock(&module_mutex);		return PTR_ERR(mod);	} 	/* Now sew it into the lists.  They won't access us, since           strong_try_module_get() will fail. */	stop_machine_run(__link_module, mod, NR_CPUS); 	/* Drop lock so they can recurse */	mutex_unlock(&module_mutex); 	blocking_notifier_call_chain(&module_notify_list,			MODULE_STATE_COMING, mod); 	/* Start the module */	if (mod->init != NULL)		ret = mod->init();	if (ret < 0) {		/* Init routine failed: abort.  Try to protect us from                   buggy refcounters. */		mod->state = MODULE_STATE_GOING;		synchronize_sched();		if (mod->unsafe)			printk(KERN_ERR "%s: module is now stuck!\n",			       mod->name);		else {			module_put(mod);			mutex_lock(&module_mutex);			free_module(mod);			mutex_unlock(&module_mutex);		}		return ret;	} 	/* Now it's a first class citizen! */	mutex_lock(&module_mutex);	mod->state = MODULE_STATE_LIVE;	/* Drop initial reference. */	module_put(mod);	module_free(mod, mod->module_init);	mod->module_init = NULL;	mod->init_size = 0;	mod->init_text_size = 0;	mutex_unlock(&module_mutex); 	return 0;} static inline int within(unsigned long addr, void *start, unsigned long size){	return ((void *)addr >= start && (void *)addr < start + size);} #ifdef CONFIG_KALLSYMS/* * This ignores the intensely annoying "mapping symbols" found * in ARM ELF files: $a, $t and $d. */static inline int is_arm_mapping_symbol(const char *str){	return str[0] == '$' && strchr("atd", str[1]) 	       && (str[2] == '\0' || str[2] == '.');} static const char *get_ksymbol(struct module *mod,			       unsigned long addr,			       unsigned long *size,			       unsigned long *offset){	unsigned int i, best = 0;	unsigned long nextval; 	/* At worse, next value is at end of module */	if (within(addr, mod->module_init, mod->init_size))		nextval = (unsigned long)mod->module_init+mod->init_text_size;	else 		nextval = (unsigned long)mod->module_core+mod->core_text_size; 	/* Scan for closest preceeding symbol, and next symbol. (ELF           starts real symbols at 1). */	for (i = 1; i < mod->num_symtab; i++) {		if (mod->symtab[i].st_shndx == SHN_UNDEF)			continue; 		/* We ignore unnamed symbols: they're uninformative		 * and inserted at a whim. */		if (mod->symtab[i].st_value <= addr		    && mod->symtab[i].st_value > mod->symtab[best].st_value		    && *(mod->strtab + mod->symtab[i].st_name) != '\0'		    && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name))			best = i;		if (mod->symtab[i].st_value > addr		    && mod->symtab[i].st_value < nextval		    && *(mod->strtab + mod->symtab[i].st_name) != '\0'		    && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name))			nextval = mod->symtab[i].st_value;	} 	if (!best)		return NULL; 	*size = nextval - mod->symtab[best].st_value;	*offset = addr - mod->symtab[best].st_value;	return mod->strtab + mod->symtab[best].st_name;} /* For kallsyms to ask for address resolution.  NULL means not found.   We don't lock, as this is used for oops resolution and races are a   lesser concern. */const char *module_address_lookup(unsigned long addr,				  unsigned long *size,				  unsigned long *offset,				  char **modname){	struct module *mod; 	list_for_each_entry(mod, &modules, list) {		if (within(addr, mod->module_init, mod->init_size)		    || within(addr, mod->module_core, mod->core_size)) {			*modname = mod->name;			return get_ksymbol(mod, addr, size, offset);		}	}	return NULL;} struct module *module_get_kallsym(unsigned int symnum,				  unsigned long *value,				  char *type,				  char namebuf[128]){	struct module *mod; 	mutex_lock(&module_mutex);	list_for_each_entry(mod, &modules, list) {		if (symnum < mod->num_symtab) {			*value = mod->symtab[symnum].st_value;			*type = mod->symtab[symnum].st_info;			strncpy(namebuf,				mod->strtab + mod->symtab[symnum].st_name,				127);			mutex_unlock(&module_mutex);			return mod;		}		symnum -= mod->num_symtab;	}	mutex_unlock(&module_mutex);	return NULL;} static unsigned long mod_find_symname(struct module *mod, const char *name){	unsigned int i; 	for (i = 0; i < mod->num_symtab; i++)		if (strcmp(name, mod->strtab+mod->symtab[i].st_name) == 0 &&		    mod->symtab[i].st_info != 'U')			return mod->symtab[i].st_value;	return 0;} /* Look for this name: can be of form module:name. */unsigned long module_kallsyms_lookup_name(const char *name){	struct module *mod;	char *colon;	unsigned long ret = 0; 	/* Don't lock: we're in enough trouble already. */	if ((colon = strchr(name, ':')) != NULL) {		*colon = '\0';		if ((mod = find_module(name)) != NULL)			ret = mod_find_symname(mod, colon+1);		*colon = ':';	} else {		list_for_each_entry(mod, &modules, list)			if ((ret = mod_find_symname(mod, name)) != 0)				break;	}	return ret;}#endif /* CONFIG_KALLSYMS */ /* Called by the /proc file system to return a list of modules. */static void *m_start(struct seq_file *m, loff_t *pos){	struct list_head *i;	loff_t n = 0; 	mutex_lock(&module_mutex);	list_for_each(i, &modules) {		if (n++ == *pos)			break;	}	if (i == &modules)		return NULL;	return i;} static void *m_next(struct seq_file *m, void *p, loff_t *pos){

Lines 1501–2000 of 2126. Previous lines