⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 module.c

📁 Kernel code of linux kernel
💻 C
📖 第 1 页 / 共 5 页
字号:
			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_update_bounds(mod->core_size);	if (!ptr) {		err = -ENOMEM;		goto free_percpu;	}	memset(ptr, 0, mod->core_size);	mod->module_core = ptr;	ptr = module_alloc_update_bounds(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);	/* add kobject, so we can reference it. */	err = mod_sysfs_init(mod);	if (err)		goto free_unload;	/* Set up license info based on the info section */	set_license(mod, get_modinfo(sechdrs, infoindex, "license"));	/*	 * 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);	/* 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_UNUSED_SYMBOLS	mod->num_unused_syms = sechdrs[unusedindex].sh_size /					sizeof(*mod->unused_syms);	mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size /					sizeof(*mod->unused_gpl_syms);	mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr;	if (unusedcrcindex)		mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr;	mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr;	if (unusedgplcrcindex)		mod->unused_gpl_crcs			= (void *)sechdrs[unusedgplcrcindex].sh_addr;#endif#ifdef CONFIG_MODVERSIONS	if ((mod->num_syms && !crcindex)	    || (mod->num_gpl_syms && !gplcrcindex)	    || (mod->num_gpl_future_syms && !gplfuturecrcindex)#ifdef CONFIG_UNUSED_SYMBOLS	    || (mod->num_unused_syms && !unusedcrcindex)	    || (mod->num_unused_gpl_syms && !unusedgplcrcindex)#endif		) {		printk(KERN_WARNING "%s: No versions for exported symbols.\n", mod->name);		err = try_to_force_load(mod, "nocrc");		if (err)			goto cleanup;	}#endif	markersindex = find_sec(hdr, sechdrs, secstrings, "__markers"); 	markersstringsindex = find_sec(hdr, sechdrs, secstrings,					"__markers_strings");	/* 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;	}#ifdef CONFIG_MARKERS	mod->markers = (void *)sechdrs[markersindex].sh_addr;	mod->num_markers =		sechdrs[markersindex].sh_size / sizeof(*mod->markers);#endif        /* 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);#ifdef CONFIG_MARKERS	if (!mod->taints)		marker_update_probe_range(mod->markers,			mod->markers + mod->num_markers);#endif	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);	/* Now sew it into the lists so we can get lockdep and oops         * info during argument parsing.  Noone should access us, since         * strong_try_module_get() will fail. */	stop_machine(__link_module, mod, NULL);	/* 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 unlink;	err = mod_sysfs_setup(mod,			      (struct kernel_param *)			      sechdrs[setupindex].sh_addr,			      sechdrs[setupindex].sh_size			      / sizeof(struct kernel_param));	if (err < 0)		goto unlink;	add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);	add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs);	/* Size of section 0 is 0, so this works well if no unwind info. */	mod->unwind_info = unwind_add_table(mod,					    (void *)sechdrs[unwindex].sh_addr,					    sechdrs[unwindex].sh_size);	/* Get rid of temporary copy */	vfree(hdr);	/* Done! */	return mod; unlink:	stop_machine(__unlink_module, mod, NULL);	module_arch_cleanup(mod); cleanup:	kobject_del(&mod->mkobj.kobj);	kobject_put(&mod->mkobj.kobj); free_unload:	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;}/* 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);	}	/* 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 = do_one_initcall(mod->init);	if (ret < 0) {		/* Init routine failed: abort.  Try to protect us from                   buggy refcounters. */		mod->state = MODULE_STATE_GOING;		synchronize_sched();		module_put(mod);		blocking_notifier_call_chain(&module_notify_list,					     MODULE_STATE_GOING, mod);		mutex_lock(&module_mutex);		free_module(mod);		mutex_unlock(&module_mutex);		wake_up(&module_wq);		return ret;	}	if (ret > 0) {		printk(KERN_WARNING "%s: '%s'->init suspiciously returned %d, "				    "it should follow 0/-E convention\n"		       KERN_WARNING "%s: loading module anyway...\n",		       __func__, mod->name, ret,		       __func__);		dump_stack();	}	/* Now it's a first class citizen!  Wake up anyone waiting for it. */	mod->state = MODULE_STATE_LIVE;	wake_up(&module_wq);	mutex_lock(&module_mutex);	/* Drop initial reference. */	module_put(mod);	unwind_remove_table(mod->unwind_info, 1);	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;	if (size)		*size = nextval - mod->symtab[best].st_value;	if (offset)		*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.  Careful * not to lock to avoid deadlock on oopses, simply disable preemption. */const char *module_address_lookup(unsigned long addr,			    unsigned long *size,			    unsigned long *offset,			    char **modname,			    char *namebuf){	struct module *mod;	const char *ret = NULL;	preempt_disable();	list_for_each_entry(mod, &modules, list) {		if (within(addr, mod->module_init, mod->init_size)		    || within(addr, mod->module_core, mod->core_size)) {			if (modname)				*modname = mod->name;			ret = get_ksymbol(mod, addr, size, offset);			break;		}	}	/* Make a copy in here where it's safe */	if (ret) {		strncpy(namebuf, ret, KSYM_NAME_LEN - 1);		ret = namebuf;	}	preempt_enable();	return ret;}int lookup_module_symbol_name(unsigned long addr, char *symname){	struct module *mod;	preempt_disable();	list_for_each_entry(mod, &modules, list) {		if (within(addr, mod->module_init, mod->init_size) ||		    within(addr, mod->module_core, mod->core_size)) {			const char *sym;			sym = get_ksymbol(mod, addr, NULL, NULL);			if (!sym)				goto out;			strlcpy(symname, sym, KSYM_NAME_LEN);			preempt_enable();			return 0;		}	}out:	preempt_enable();	return -ERANGE;}int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,			unsigned long *offset, char *modname, char *name){	struct module *mod;	preempt_disable();	list_for_each_entry(mod, &modules, list) {		if (within(addr, mod->module_init, mod->init_size) ||		    within(addr, mod->module_core, mod->core_size)) {			const char *sym;			sym = get_ksymbol(mod, addr, size, offset);			if (!sym)				goto out;			if (modname)				strlcpy(modname, mod->name, MODULE_NAME_LEN);			if (name)				strlcpy(name, sym, KSYM_NAME_LEN);			preempt_enable();			return 0;		}	}out:	preempt_enable();	return -ERANGE;}int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,			char *name, char *module_name, int *exported){	struct module *mod;	preempt_disable();	list_for_each_entry(mod, &modules, list) {		if (symnum < mod->num_symtab) {			*value = mod->symtab[symnum].st_value;			*type = mod->symtab[symnum].st_info;		

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -