3539 lines · 89.7 KB · C
RawDownload
	list_for_each_entry(use, &mod->target_list, target_list)		sysfs_remove_link(use->target->holders_dir, mod->name);	mutex_unlock(&module_mutex);#endif} static int module_add_modinfo_attrs(struct module *mod){	struct module_attribute *attr;	struct module_attribute *temp_attr;	int error = 0;	int i; 	mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *					(ARRAY_SIZE(modinfo_attrs) + 1)),					GFP_KERNEL);	if (!mod->modinfo_attrs)		return -ENOMEM; 	temp_attr = mod->modinfo_attrs;	for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {		if (!attr->test ||		    (attr->test && attr->test(mod))) {			memcpy(temp_attr, attr, sizeof(*temp_attr));			sysfs_attr_init(&temp_attr->attr);			error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr);			++temp_attr;		}	}	return error;} static void module_remove_modinfo_attrs(struct module *mod){	struct module_attribute *attr;	int i; 	for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {		/* pick a field to test for end of list */		if (!attr->attr.name)			break;		sysfs_remove_file(&mod->mkobj.kobj,&attr->attr);		if (attr->free)			attr->free(mod);	}	kfree(mod->modinfo_attrs);} static int mod_sysfs_init(struct module *mod){	int err;	struct kobject *kobj; 	if (!module_sysfs_initialized) {		printk(KERN_ERR "%s: module sysfs not initialized\n",		       mod->name);		err = -EINVAL;		goto out;	} 	kobj = kset_find_obj(module_kset, mod->name);	if (kobj) {		printk(KERN_ERR "%s: module is already loaded\n", mod->name);		kobject_put(kobj);		err = -EINVAL;		goto out;	} 	mod->mkobj.mod = mod; 	memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));	mod->mkobj.kobj.kset = module_kset;	err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,				   "%s", mod->name);	if (err)		kobject_put(&mod->mkobj.kobj); 	/* delay uevent until full sysfs population */out:	return err;} static int mod_sysfs_setup(struct module *mod,			   const struct load_info *info,			   struct kernel_param *kparam,			   unsigned int num_params){	int err; 	err = mod_sysfs_init(mod);	if (err)		goto out; 	mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);	if (!mod->holders_dir) {		err = -ENOMEM;		goto out_unreg;	} 	err = module_param_sysfs_setup(mod, kparam, num_params);	if (err)		goto out_unreg_holders; 	err = module_add_modinfo_attrs(mod);	if (err)		goto out_unreg_param; 	add_usage_links(mod);	add_sect_attrs(mod, info);	add_notes_attrs(mod, info); 	kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD);	return 0; out_unreg_param:	module_param_sysfs_remove(mod);out_unreg_holders:	kobject_put(mod->holders_dir);out_unreg:	kobject_put(&mod->mkobj.kobj);out:	return err;} static void mod_sysfs_fini(struct module *mod){	remove_notes_attrs(mod);	remove_sect_attrs(mod);	kobject_put(&mod->mkobj.kobj);} #else /* !CONFIG_SYSFS */ static int mod_sysfs_setup(struct module *mod,			   const struct load_info *info,			   struct kernel_param *kparam,			   unsigned int num_params){	return 0;} static void mod_sysfs_fini(struct module *mod){} static void module_remove_modinfo_attrs(struct module *mod){} static void del_usage_links(struct module *mod){} #endif /* CONFIG_SYSFS */ static void mod_sysfs_teardown(struct module *mod){	del_usage_links(mod);	module_remove_modinfo_attrs(mod);	module_param_sysfs_remove(mod);	kobject_put(mod->mkobj.drivers_dir);	kobject_put(mod->holders_dir);	mod_sysfs_fini(mod);} /* * unlink the module with the whole machine is stopped with interrupts off * - this defends against kallsyms not taking locks */static int __unlink_module(void *_mod){	struct module *mod = _mod;	list_del(&mod->list);	module_bug_cleanup(mod);	return 0;} #ifdef CONFIG_DEBUG_SET_MODULE_RONX/* * LKM RO/NX protection: protect module's text/ro-data * from modification and any data from execution. */void set_page_attributes(void *start, void *end, int (*set)(unsigned long start, int num_pages)){	unsigned long begin_pfn = PFN_DOWN((unsigned long)start);	unsigned long end_pfn = PFN_DOWN((unsigned long)end); 	if (end_pfn > begin_pfn)		set(begin_pfn << PAGE_SHIFT, end_pfn - begin_pfn);} static void set_section_ro_nx(void *base,			unsigned long text_size,			unsigned long ro_size,			unsigned long total_size){	/* begin and end PFNs of the current subsection */	unsigned long begin_pfn;	unsigned long end_pfn; 	/*	 * Set RO for module text and RO-data:	 * - Always protect first page.	 * - Do not protect last partial page.	 */	if (ro_size > 0)		set_page_attributes(base, base + ro_size, set_memory_ro); 	/*	 * Set NX permissions for module data:	 * - Do not protect first partial page.	 * - Always protect last page.	 */	if (total_size > text_size) {		begin_pfn = PFN_UP((unsigned long)base + text_size);		end_pfn = PFN_UP((unsigned long)base + total_size);		if (end_pfn > begin_pfn)			set_memory_nx(begin_pfn << PAGE_SHIFT, end_pfn - begin_pfn);	}} static void unset_module_core_ro_nx(struct module *mod){	set_page_attributes(mod->module_core + mod->core_text_size,		mod->module_core + mod->core_size,		set_memory_x);	set_page_attributes(mod->module_core,		mod->module_core + mod->core_ro_size,		set_memory_rw);} static void unset_module_init_ro_nx(struct module *mod){	set_page_attributes(mod->module_init + mod->init_text_size,		mod->module_init + mod->init_size,		set_memory_x);	set_page_attributes(mod->module_init,		mod->module_init + mod->init_ro_size,		set_memory_rw);} /* Iterate through all modules and set each module's text as RW */void set_all_modules_text_rw(void){	struct module *mod; 	mutex_lock(&module_mutex);	list_for_each_entry_rcu(mod, &modules, list) {		if ((mod->module_core) && (mod->core_text_size)) {			set_page_attributes(mod->module_core,						mod->module_core + mod->core_text_size,						set_memory_rw);		}		if ((mod->module_init) && (mod->init_text_size)) {			set_page_attributes(mod->module_init,						mod->module_init + mod->init_text_size,						set_memory_rw);		}	}	mutex_unlock(&module_mutex);} /* Iterate through all modules and set each module's text as RO */void set_all_modules_text_ro(void){	struct module *mod; 	mutex_lock(&module_mutex);	list_for_each_entry_rcu(mod, &modules, list) {		if ((mod->module_core) && (mod->core_text_size)) {			set_page_attributes(mod->module_core,						mod->module_core + mod->core_text_size,						set_memory_ro);		}		if ((mod->module_init) && (mod->init_text_size)) {			set_page_attributes(mod->module_init,						mod->module_init + mod->init_text_size,						set_memory_ro);		}	}	mutex_unlock(&module_mutex);}#elsestatic inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { }static void unset_module_core_ro_nx(struct module *mod) { }static void unset_module_init_ro_nx(struct module *mod) { }#endif void __weak module_free(struct module *mod, void *module_region){	vfree(module_region);} void __weak module_arch_cleanup(struct module *mod){} /* Free a module, remove from lists, etc. */static void free_module(struct module *mod){	trace_module_free(mod); 	/* Delete from various lists */	mutex_lock(&module_mutex);	stop_machine(__unlink_module, mod, NULL);	mutex_unlock(&module_mutex);	mod_sysfs_teardown(mod); 	/* Remove dynamic debug info */	ddebug_remove_module(mod->name); 	/* Arch-specific cleanup. */	module_arch_cleanup(mod); 	/* Module unload stuff */	module_unload_free(mod); 	/* Free any allocated parameters. */	destroy_params(mod->kp, mod->num_kp); 	/* This may be NULL, but that's OK */	unset_module_init_ro_nx(mod);	module_free(mod, mod->module_init);	kfree(mod->args);	percpu_modfree(mod); 	/* Free lock-classes: */	lockdep_free_key_range(mod->module_core, mod->core_size); 	/* Finally, free the core (containing the module structure) */	unset_module_core_ro_nx(mod);	module_free(mod, mod->module_core); #ifdef CONFIG_MPU	update_protections(current->mm);#endif} void *__symbol_get(const char *symbol){	struct module *owner;	const struct kernel_symbol *sym; 	preempt_disable();	sym = find_symbol(symbol, &owner, NULL, true, true);	if (sym && strong_try_module_get(owner))		sym = NULL;	preempt_enable(); 	return sym ? (void *)sym->value : NULL;}EXPORT_SYMBOL_GPL(__symbol_get); /* * Ensure that an exported symbol [global namespace] does not already exist * in the kernel or in some other module's exported symbol table. * * You must hold the module_mutex. */static int verify_export_symbols(struct module *mod){	unsigned int i;	struct module *owner;	const struct kernel_symbol *s;	struct {		const struct kernel_symbol *sym;		unsigned int num;	} arr[] = {		{ mod->syms, mod->num_syms },		{ mod->gpl_syms, mod->num_gpl_syms },		{ mod->gpl_future_syms, mod->num_gpl_future_syms },#ifdef CONFIG_UNUSED_SYMBOLS		{ mod->unused_syms, mod->num_unused_syms },		{ mod->unused_gpl_syms, mod->num_unused_gpl_syms },#endif	}; 	for (i = 0; i < ARRAY_SIZE(arr); i++) {		for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {			if (find_symbol(s->name, &owner, NULL, true, false)) {				printk(KERN_ERR				       "%s: exports duplicate symbol %s"				       " (owned by %s)\n",				       mod->name, s->name, module_name(owner));				return -ENOEXEC;			}		}	}	return 0;} /* Change all symbols so that st_value encodes the pointer directly. */static int simplify_symbols(struct module *mod, const struct load_info *info){	Elf_Shdr *symsec = &info->sechdrs[info->index.sym];	Elf_Sym *sym = (void *)symsec->sh_addr;	unsigned long secbase;	unsigned int i;	int ret = 0;	const struct kernel_symbol *ksym; 	for (i = 1; i < symsec->sh_size / sizeof(Elf_Sym); i++) {		const char *name = info->strtab + sym[i].st_name; 		switch (sym[i].st_shndx) {		case SHN_COMMON:			/* We compiled with -fno-common.  These are not			   supposed to happen.  */			pr_debug("Common symbol: %s\n", name);			printk("%s: please compile with -fno-common\n",			       mod->name);			ret = -ENOEXEC;			break; 		case SHN_ABS:			/* Don't need to do anything */			pr_debug("Absolute symbol: 0x%08lx\n",			       (long)sym[i].st_value);			break; 		case SHN_UNDEF:			ksym = resolve_symbol_wait(mod, info, name);			/* Ok if resolved.  */			if (ksym && !IS_ERR(ksym)) {				sym[i].st_value = ksym->value;				break;			} 			/* Ok if weak.  */			if (!ksym && ELF_ST_BIND(sym[i].st_info) == STB_WEAK)				break; 			printk(KERN_WARNING "%s: Unknown symbol %s (err %li)\n",			       mod->name, name, PTR_ERR(ksym));			ret = PTR_ERR(ksym) ?: -ENOENT;			break; 		default:			/* Divert to percpu allocation if a percpu var. */			if (sym[i].st_shndx == info->index.pcpu)				secbase = (unsigned long)mod_percpu(mod);			else				secbase = info->sechdrs[sym[i].st_shndx].sh_addr;			sym[i].st_value += secbase;			break;		}	} 	return ret;} int __weak apply_relocate(Elf_Shdr *sechdrs,			  const char *strtab,			  unsigned int symindex,			  unsigned int relsec,			  struct module *me){	pr_err("module %s: REL relocation unsupported\n", me->name);	return -ENOEXEC;} int __weak apply_relocate_add(Elf_Shdr *sechdrs,			      const char *strtab,			      unsigned int symindex,			      unsigned int relsec,			      struct module *me){	pr_err("module %s: RELA relocation unsupported\n", me->name);	return -ENOEXEC;} static int apply_relocations(struct module *mod, const struct load_info *info){	unsigned int i;	int err = 0; 	/* Now do relocations. */	for (i = 1; i < info->hdr->e_shnum; i++) {		unsigned int infosec = info->sechdrs[i].sh_info; 		/* Not a valid relocation section? */		if (infosec >= info->hdr->e_shnum)			continue; 		/* Don't bother with non-allocated sections */		if (!(info->sechdrs[infosec].sh_flags & SHF_ALLOC))			continue; 		if (info->sechdrs[i].sh_type == SHT_REL)			err = apply_relocate(info->sechdrs, info->strtab,					     info->index.sym, i, mod);		else if (info->sechdrs[i].sh_type == SHT_RELA)			err = apply_relocate_add(info->sechdrs, info->strtab,						 info->index.sym, i, mod);		if (err < 0)			break;	}	return err;} 

Lines 1501–2000 of 3539. Previous lines